Рассмотрим следующий пример:
#include <cstdlib>
struct A
{
A(int, char*){};
A(const A&){ printf("copy-ctor\n"); }
};
int main()
{
A x = A(5, nullptr);
}
Согласно 8.5.16 (стандарта C ++ 11) строка
A x = A(5, nullptr);
рассматривается как
A x(A(5, nullptr));
(то есть временный объект типа A создается и передается copy-ctor типа A для инициализации x). Тогда согласно 12.8.31 допускается компилятор (но не принудительно) выполнить оптимизацию под названием «исключение копирования», чтобы исключить создание временного типа A, который эффективно превращает эту строку кода в
A x(5, nullptr);
(т. е. не создаются временные файлы, не называются копи-ctors).
Теперь предположим, что я использую инициализацию списка в приведенном выше примере следующим образом:
A x = {5, nullptr}; // (1)
или же
A x = A{5, nullptr}; // (2)
Может кто-нибудь, пожалуйста процитировать соответствующие фараграфы из стандарта C ++ 11 которые подтверждают или опровергают, что (1) и / или (2) всегда (то есть, не только когда компилятор может выполнить оптимизацию «copy elision»), должен рассматриваться как
A x(5, nullptr);
(то есть первый конструктор A вызывается напрямую, временные файлы не создаются, копирование объектов типа A не выполняется).
Этот ответ, по-видимому, неверен, что удивило меня, чтобы узнать. Смотрите комментарии. Я думаю, что первая и четвертая маркированные точки в [dcl.init.list] / 3 — это то, что означает (1), вызывает конструктор (или выполняет агрегатную инициализацию) напрямую, без временной.
В стандарте нет ничего, что гарантировало бы, что (1) и (2) избегают временного. Они оба являются инициализацией копирования, (1) инициализацией списка копирования, как определено в [dcl.init.list] p1:
Инициализация списка может происходить в контексте прямой инициализации или инициализации копирования; инициализация списка в контексте прямой инициализации называется прямой список инициализация и инициализация списка в контексте инициализации копирования называется копирование списка инициализация.
В обоих случаях это инициализация копирования, и [dcl.init] говорит, что это может включать перемещение (которое может быть исключено).
8.5/14,15
:
Инициализация, которая происходит в форме
[…] называется copy-initialization.
T x = a;
Инициализация, которая происходит в формах
T x(a);
[…] называется прямой инициализацией.
T x{a};
Если ваш компилятор не достаточно умен, чтобы всегда исключать временное, то для обеспечения отсутствия временного с инициализацией списка вы можете использовать прямую инициализацию списка, т.е.
A x{5, nullptr};
Других решений пока нет …