C++(11): когда использовать прямую или копировать инициализацию, если оба в порядке

До того, как начнутся крики о дублировании: я знаю, что следующий вопрос (и некоторые другие) довольно тесно связаны с этим:

Есть ли разница в C++ между инициализацией копирования и прямой инициализацией?

Ответы на этот вопрос прекрасно объясняют сценарии, в которых инициализация копирования невозможна, и объясняют разницу между этими двумя вещами. Однако мой вопрос более тонкий:

Рассмотрим код:

A createA(){...}

A a1 = createA();
A a2(createA());

Предположим, что A может быть неявно сконструирован с помощью копирования и тому подобного, поэтому обе инициализации a1 а также a2 в порядке. Там нет никаких побочных эффектов в конструкторе копирования для Aпоэтому обе инициализации также семантически эквивалентны. createA() возвращает непосредственно тип переменной, а не что-то еще, что должно быть приведено первым. Я думаю, что этот случай довольно распространен.

Итак, в этом случае, где обе альтернативы одинаково применимы и семантически эквивалентны, какой из них мне следует использовать? Есть ли рекомендация в спецификации или консенсус / лучшая практика в сообществе, или это только от меня и моего стиля кодирования, какой использовать? Введены ли в C++11 какие-либо различия по сравнению со старыми стандартами?

2 ответа

Решение

Нет всегда лучшего ответа, это вопрос стиля.

При инициализации объекта из простого выражения типа объекта (например, createA()) Я часто использую copy-init, вероятно, просто из-за знакомства с = форма назначения. В противном случае, когда инициализатор другого типа или имеется несколько инициализаторов для объекта (например, несколько аргументов конструктора или агрегатный init), я предпочитаю использовать C++11 list-initialization (так называемый унифицированный синтаксис инициализации), который можно использовать в больше мест, например, для инициализации агрегатов, а также классов с определяемыми пользователем конструкторами, и не могут быть проанализированы как объявление функции:

A a1{ createA() };

Приведенная выше форма list-init использует direct-init, тогда как эта форма использует copy-init:

A a2 = { createA() };

При использовании list-init я предпочитаю форму direct-init без избыточности = знак.

Есть несколько случаев, когда list-init невозможен, например, когда тип имеет конструктор initializer-list (т.е. тот, который принимает параметр, который является специализацией std::initializer_list) и вы хотите вызвать другой конструктор, но будет выбран конструктор списка инициализатора, например std::vector<int> v{ 5u, 0 }; не будет создавать вектор из пяти элементов со значением ноль, но вектор с двумя элементами со значениями пять и ноль

Если все остальное одинаково (семантика, производительность,...), это, очевидно, только вопрос вкуса и / или стиля. Однако многие авторы рекомендуют инициализировать список для прямой инициализации в эти дни:

A a3 {createA()};

Но я бы сказал, что вам решать (если это ваш забавный проект) или вашим коллегам выбрать одну из двух (трех) альтернатив. Я бы не рекомендовал использовать их как взаимозаменяемые, потому что это заставит читателей задуматься, почему вы используете иногда прямую, а иногда копируемую инициализацию.

Другие вопросы по тегам