Инициализатор конструктора не вызывает конструктор копирования - программирование
Подтвердить что ты не робот

Инициализатор конструктора не вызывает конструктор копирования

Поэтому я узнал о списке инициализаторов конструктора и написал следующий код:

class Mango
{
  public:

  Mango(){cout<<"Mango::ctor()";}
  Mango(const Mango& other){cout<<"Mango::copy_ctor()";}
};

class Box
{
    public:

    Box() : mango(Mango()) //**doesn't call copy constructor**
    {
    }

    Mango mango;
};

int main()
{
  Box box; 

   return 0;
}

Для этого я использовал компилятор g++. Его вызов конструктор не копирует конструктор. Он должен вызвать конструктор копирования правильно, потому что я создаю объект для создания другого объекта? Какая проблема здесь и что говорит об этом стандарт?

4b9b3361

Ответ 1

Из-за копирования, конструкция copy- здесь опущена. Такое поведение гарантируется на С++ 17. Перед С++ 17 это не обязательно; компиляторы разрешены, но не требуются для выполнения копии 1.

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

  • При инициализации, если выражение инициализатора является prvalue, а cv-неквалифицированная версия типа источника является тем же классом, что и класс назначения, выражение инициализатора используется для инициализации целевого объекта:

    T x = T(T(T())); // only one call to default constructor of T, to initialize x
    

Это означает, что mango будет инициализироваться конструктором по умолчанию напрямую.


[1] На самом деле большинство реализаций также выполняли бы проверку подлинности до С++ 17. С Gcc вы можете попробовать с -fno-elide-constructors в режиме pre-С++ 17, чтобы отключить копирование.

Ответ 2

Поскольку songyuanyao уже так хорошо объяснил в своем превосходном ответе, компилятору разрешено оптимизировать вызов вызова конструктора копирования в ряде случаев.

Тем не менее, я хотел бы затронуть другую часть вашего вопроса, на случай, если возникнут некоторые недоразумения:

Для этого я использовал компилятор g++. Его вызов конструктор не копирует конструктор. Он должен вызвать конструктор копирования правильно, потому что я создаю объект для создания другого объекта? Какая проблема здесь и что говорит об этом стандарт?

Чтобы вызвать вызов, для вашего конструктора копирования необходимо предоставить (const Mango& other). Если компилятор не выполнил бы копию elision, вы сначала увидите вызов "нормального" конструктора "Mango::ctor()" за которым следует вызов конструктора-копии "Mango::copy_ctor()". Копирование elision просто оптимизирует ненужный вызов конструктора-копии - конструктор для объекта должен быть вызван в любом случае, чтобы получить объект Mango() в Box(): mango(Mango())