[...] сможет ли компилятор оптимизировать дополнительные инициализации?
Почти во всех случаях: да.
Должен ли я всегда писать свои конструкторы перемещения, вызывая оператор присваивания перемещения?
Да, просто реализуйте его с помощью оператора присваивания перемещения, за исключением случаев, когда вы измерили, что это приводит к неоптимальной производительности.
Современные оптимизаторы проделывают невероятную работу по оптимизации кода. Код вашего примера особенно легко оптимизировать. Прежде всего: конструктор перемещения будет встроен почти во всех случаях. Если вы реализуете его с помощью оператора присваивания перемещения, он также будет встроен.
А давайте посмотрим на какую-нибудь сборку! Это показывает точный код с веб-сайта Microsoft с обеими версиями конструктора перемещения: вручную и с помощью назначения перемещения. Вот вывод сборки для GCC с -O
(у -O1
такой же вывод; вывод clang приводит к тому же выводу):
; ===== manual version ===== | ; ===== via move-assig =====
MemoryBlock(MemoryBlock&&): | MemoryBlock(MemoryBlock&&):
mov QWORD PTR [rdi], 0 | mov QWORD PTR [rdi], 0
mov QWORD PTR [rdi+8], 0 | mov QWORD PTR [rdi+8], 0
| cmp rdi, rsi
| je .L1
mov rax, QWORD PTR [rsi+8] | mov rax, QWORD PTR [rsi+8]
mov QWORD PTR [rdi+8], rax | mov QWORD PTR [rdi+8], rax
mov rax, QWORD PTR [rsi] | mov rax, QWORD PTR [rsi]
mov QWORD PTR [rdi], rax | mov QWORD PTR [rdi], rax
mov QWORD PTR [rsi+8], 0 | mov QWORD PTR [rsi+8], 0
mov QWORD PTR [rsi], 0 | mov QWORD PTR [rsi], 0
| .L1:
ret | rep ret
Не считая дополнительной ветки для нужной версии, код точно такой же. Значение: повторяющиеся задания удалены.
Зачем дополнительная ветка? Оператор присваивания перемещения, определенный на странице Microsoft, выполняет больше работы, чем конструктор перемещения: он защищен от самоприсваивания. Конструктор перемещения не защищен от этого. Но: как я уже сказал, конструктор будет встроен почти во всех случаях. И в этих случаях оптимизатор может увидеть, что это не самоназначение, поэтому эта ветвь тоже будет оптимизирована.
Это часто повторяется, но важно: не делайте преждевременной микрооптимизации!
Не поймите меня неправильно, я также ненавижу программное обеспечение, которое тратит впустую много ресурсов из-за ленивых или небрежных разработчиков или управленческих решений. А энергосбережение — это не только батарейки, но и экологическая тема, которой я очень увлечен. Но преждевременная микрооптимизация не помогает в этом отношении! Конечно, держите в уме алгоритмическую сложность и удобство кэширования больших данных. Но прежде чем выполнять какую-либо конкретную оптимизацию, измерьте!
В этом конкретном случае, я бы даже предположил, что вам никогда не придется вручную оптимизировать, потому что компилятор всегда сможет сгенерировать оптимальный код вокруг вашего конструктора перемещения. Выполнение бесполезной микрооптимизации сейчас будет стоить вам времени на разработку позже, когда вам нужно будет изменить код в двух местах или когда вам нужно отладить странную ошибку, которая возникает только потому, что вы изменили код только в одном месте. И это пустая трата времени на разработку, которое можно было бы потратить на полезную оптимизацию.
person
Lukas Kalbertodt
schedule
08.12.2018