Синтаксис инициализации объекта в C ++ (T obj = {...} против T obj {...}) - PullRequest
2 голосов
/ 23 марта 2020

В чем разница между двумя формами инициализации, T obj = {...} и T obj{...}?
Я изначально думал, что T obj = {...} было сокращением для T obj = T{...}, когда временный объект копируется в наш новый объект. Это, хотя и не выполняет конструктор копирования ( copy elision ), требует его существования и доступа к нему. Но когда я заблокировал доступ к конструктору копирования в этом конкретном классе, сделав конструктор закрытым, ошибки не было.
Это означает, что механизм копирования не задействован. Так какова функция символа '='?
Я упомянул следующий вопрос, но был недоволен из-за отсутствия объяснения:
Является ли C ++ 11 Uniform Initialization заменой старого синтаксис стиля?

РЕДАКТИРОВАТЬ: Есть ли на аналогичной ноте разница между int arr[]{...} и int arr[] = {...}? Я прошу это посмотреть, смогу ли я выявить контраст между равномерной инициализацией и инициализацией списка.

Ответы [ 2 ]

2 голосов
/ 23 марта 2020

Я думаю, что сравнение этих двух синтаксисов не является вашим реальным вопросом.

Мне кажется, что вы ожидаете, что элита C ++ 17 будет вести себя так же, как допускалась "оптимизация" до C ++ 17 по стандарту и выполняется многими реализациями.

В этой «оптимизации», хотя вызов конструктора копирования можно было исключить, он должен быть действительным и доступным.

С C ++ 17 elision это не так.

Это истинное допущение, когда просто написание T{} на самом деле не создает T, а вместо этого говорит: Я хочу T ", а фактическое временное явление" материализуется "только тогда, когда это необходимо.

Избыточные высказывания этого факта фактически сводятся в одно целое, поэтому, несмотря на крики" Я хочу T ! Я хочу T! Я хочу T! Я хочу T! " ребенок все еще получает только один T в конце. 10

Итак, в C ++ 17 T obj = T{...} буквально эквивалентно T obj{...}.

Это объясняет результаты, которые вы видите, и ваше замешательство.


Вы можете узнать больше об этой функции на cppreference.com ; Вот фрагмент из верхней части страницы:

Обязательное исключение операций копирования / перемещения

При следующих обстоятельствах компиляторы должны опускать Скопируйте и переместите конструкцию объектов класса, даже если конструктор копирования / перемещения и деструктор имеют заметные побочные эффекты. Объекты создаются непосредственно в хранилище, где они в противном случае были бы скопированы / перемещены. Конструкторы копирования / перемещения не обязательно должны присутствовать или быть доступными:

  • [..]
  • При инициализации объекта, когда выражение инициализатора представляет собой prvalue того же типа класса (игнорируя квалификацию cv), что и тип переменной [..]
2 голосов
/ 23 марта 2020

Они имеют почти точно такой же эффект:

  • T x = { 1, 2, 3 };
  • T x { 1, 2, 3 };

Технически версия с = называется copy-list-initialization , а другая версия direct-list-initialization , но поведение обеих этих форм определяется списком инициализация поведения.

Различия:

  • Если copy-list-initialization выбирает конструктор explicit, то код неверен.
  • Если T равно auto, то:
    • copy-list-initialization выводит std::initializer_list<Type_of_element>
    • direct-list-initialization допускает только один элемент в списке и выводит Type_of_element.

Дополнительная информация: Почему стандарт различает прямую инициализацию списка и инициализацию копирования списка?


Если T является типом массива, вышеупомянутое все еще применяется; поскольку инициализация списка массивов всегда является агрегатной инициализацией, конструктор никогда не выбирается, и поэтому обе версии одинаковы во всех случаях.


T obj = T{...} (исключая auto) в точности совпадает с T obj{...}, начиная с C ++ 17, то есть прямая инициализация списка из obj. До C ++ 17 была прямая инициализация списка временного, а затем копирование-инициализация obj из временного.

...