Ответ 1
Поскольку поведение copy elision изменяется с С++ 17; для этого случая оптимизация обязательна.
При следующих обстоятельствах компиляторы должны опускать копировать и перемещать конструкторы объектов класса, даже если копировать/перемещать конструктор и деструктор имеют наблюдаемые побочные эффекты:
При инициализации, если выражение инициализатора является prvalue и cv-неквалифицированная версия типа источника - это тот же класс, что и класс адресата, выражение инициализатора используется для инициализировать объект назначения:
T x = T(T(T())); // only one call to default constructor of T, to initialize x
Эффекты инициализации копии:
Во-первых, если
T
- тип класса, а инициализатор - это prvalue выражение, чей неквалифицированный тип является тем же классом, что иT
, самого инициализатора, скорее, что временное материализованное из него используется для инициализации целевого объекта: см. copy elision (начиная с С++ 17)Если
T
- тип класса, а cv-неквалифицированная версия типа otherT
или класс, полученный изT
, неявные конструкторыT
, и наилучшее совпадение выбирается с помощью разрешения перегрузки. Затем конструктор вызывается для инициализации объекта.
Это означает, что для X a = X()
, значение a
будет построено по умолчанию напрямую, конструкторы copy/move и их побочные эффекты будут полностью исключены. Выбор неявных конструкторов для разрешения перегрузки не будет иметь места, что требуется в С++ 14 (и раньше). Для этих гарантированных случаев конструкторы copy/move не участвуют, тогда не имеет значения, являются ли они explicit
или нет.