То, что вы видите, называется copy elision в компиляторе до C ++ 17 (попробуйте это с C ++ 17 на проводнике компилятора или wandbox с -std=c++17
против -std=c++14
флагов). Начиная с C ++ 17, компилятор обязан исключать множество случаев копирования и перемещения конструкторов и создавать объекты напрямую без каких-либо промежуточных объектов.
В отличие от
A a { 10 };
линия
A a = 10;
означает, что сначала создается временный объект, как если бы код имел:
A a = A(10);
До C ++ 17 компилятор позволял оптимизировать этот код и создавать a
непосредственно из 10
без временного объекта. Обратите внимание, что акцент делается на том, что разрешено , но не требуется для выполнения этой copy elision оптимизации. Вы наблюдали эту разрешенную оптимизацию.
Компилятор должен был скомпилировать или завершить работу кода независимо от своего решения сделать копию. Если компилятор не мог вызвать конструктор копирования, как в вашем случае, то он должен был безоговорочно завершить компиляцию, даже если он решил сделать исключение копирования. Это изменилось в C ++ 17, и компилятору теперь требуется , чтобы в этом случае оптимизировать копирование. Поскольку гарантированно исключается конструктор копирования, конструктор копирования даже не требуется, и код может компилироваться без ошибки.
Обратите внимание на конструктор копирования без const:
A(A &other) { std::cout << " other " << std::endl; value = other.value; }
Без возможности копирования этот конструктор копирования нельзя использовать для:
A a = A(10);
Его нельзя использовать, потому что A (10) является временным объектом, и как таковой может быть передан в качестве параметра rvalue конструкторам и методам, таким как
A(A && other);
foo(A && other);
или передается в качестве константного ссылочного параметра для конструкторов и методов, подобных
A(const A& other);
bar(const A& other);
Но его нельзя передать как обычный изменяемый параметр (как в вашем кодовом блоке 3).
С elision copy в этих случаях он даже не пытается вызвать копию или конструктор перемещения.
Все еще нужно вызвать конструктор копирования для
A b = a;
и он может сделать это с изменяемым параметром, только потому, что a
не является ни временным, ни постоянным объектом. Если вы сделаете a
const, то код не будет скомпилирован, когда конструктор копирования не получит const (для C ++ 17 и более ранних версий):
const A a = 10;
A b = a;
// ^^ this will fail
Замечание: следующая строка гарантированно не вызовет конструктор копирования ни разу с C ++ 17:
A a = A(A(A(A(1))));