Для примитивных типов оба эквивалентны, и для пользовательских типов классов есть различие.В обоих случаях исполняемый код будет одинаковым (после выполнения базовой оптимизации), но требования к типам отличаются, если элемент, из которого мы инициализируем, не того типа, который мы создаем.
copy-initialization (T t = u;
) эквивалентен конструкции копирования из временного типа T
, который неявно преобразован из u
в t
.С другой стороны, прямая инициализация эквивалентна прямому вызову соответствующего конструктора.
Хотя в большинстве случаев не будет никакой разницы, если конструктор, который принимает u
, являетсяобъявлен explicit
или если конструктор копирования недоступен, то copy-initialization завершится ошибкой:
struct A {
explicit A( int ) {}
};
struct B {
B( int ) {}
private:
B( B const & );
};
int main() {
A a(1); // ok
B b(1); // ok
// A a2 = 1; // error: cannot convert from int to A
// B b2 = 1; // error: B( B const & ) is not accessible
}
Для некоторого исторического фона изначально примитивные типы имелибыть инициализированным с copy-initialization .Когда * initializer-list * s были добавлены к языку для инициализации атрибутов членов из класса, было решено, что примитивные типы должны быть инициализированы с тем же синтаксисом, что и классы, чтобы синтаксис в списке инициализаторов был единообразным и простым.В то же время, разрешение инициализации классов с помощью copy-initialization делает пользовательские типы ближе к примитивным типам.Различия в двух форматах инициализации очевидны: int a = 5.0;
обрабатывается как преобразование из 5.0
в int
, а затем инициализация a
из int
.То же самое касается пользовательских типов: T u = v;
обрабатывается как преобразование из v
в T
, а затем копирует конструкцию u
из этого преобразованного значения.