Все ответы, которые вы получили до сих пор, слишком сложны и / или немного вводят в заблуждение.
В первой конструкции / инициализации:
T a(10);
Происходит очень очевидная вещь.Вторая конструкция / инициализация более интересна:
T aa = 10;
Это эквивалентно:
T aa(T(10));
Это означает, что вы создаете временный объект типа T, а затем создаете aa
каккопия этого временного.Это означает, что вызывается конструктор копирования.
C ++ имеет конструктор копирования по умолчанию, который он создает для класса, когда вы явно не объявили ни одного.Таким образом, хотя первая версия class T
не имеет декларированного конструктора копирования, он все еще существует.Тот, который объявляет компилятор, имеет эту подпись T(const T &)
.
Теперь во втором случае, когда вы объявляете что-то, похожее на конструктор копирования, вы делаете аргумент T &
, а не const T &
.Это означает, что компилятор, пытаясь скомпилировать второе выражение, пытается использовать ваш конструктор копирования, а это невозможно.Он жалуется, что для конструктора копирования, который вы объявили, требуется неконстантный аргумент, а аргумент, который ему дается, является const.Так что это терпит неудачу.
Другое правило заключается в том, что после того, как компилятор преобразовал вашу инициализацию в T aa(T(10));
, ему затем разрешается преобразовать его в T aa(10);
.Это называется «копировать исключение».При определенных обстоятельствах компилятору разрешено пропускать вызовы конструктора копирования.Но он может сделать это только после того, как проверит, что выражение сформировано правильно и не генерирует никаких ошибок компилятора, когда вызов конструктора копирования все еще существует.Таким образом, это шаг оптимизации, который может точно повлиять на то, какие части программы выполняются, но не может повлиять на то, какие программы являются действительными, а какие - ошибочными (по крайней мере, с точки зрения того, компилируются они или нет).