Почему деструктор и конструктор копирования демонстрируют такое поведение с массивом объектов?

#c

#c

Вопрос:

Когда массив был инициализирован объектами anonymus, деструктор отображает допустимые значения, но я создаю массив с объектами, конструктор переопределения копирования не вызывается, а также деструктор отображает значения мусора.

Я пытался понять это, отображая значения, но все еще запутался.

 class Check{
    private:
        int a;
    public:
        Check()
        {
            this->a = 9999;
            cout << "n Default Constructor Called n";
        }
        Check(int i)
        {
            this->a = i;
        }
        Check(const Check amp; obj)
        {
            cout << "COPY CONSTRUCTORn";
        }
        ~Check()
        {
            cout << this->a<<" DESTRUCTOR  n";
        }
};

Check b[2] = {Check(5),Check(4)};
Check obj1(2);
Check obj2(3);
Check a[2] = {obj1,obj2};
  

Я ожидал вывода «КОНСТРУКТОРА КОПИРОВАНИЯ» 4 раза, но это было только два раза и никаких мусорных значений. Фактический результат показан ниже:

 COPY CONSTRUCTOR 
COPY CONSTRUCTOR 
32649 DESTRUCTOR  
-1330935392 DESTRUCTOR  
3 DESTRUCTOR  
2 DESTRUCTOR  
4 DESTRUCTOR  
5 DESTRUCTOR
  

Комментарии:

1. Значения мусора связаны с тем, что в конструкторе копирования вы не инициализируете this->a

2. @M.M можете ли вы сказать мне, почему конструктор копирования вызывается только 2 раза?

3. Выведите значение a в каждом конструкторе, и вы поймете, почему.

4. @EtiennedeMartel почему в этом случае не вызывается конструктор копирования:Проверьте b[2] = {Проверка(5),Проверка(4)};»

5. @usamamw141 это называется устранением копирования . Объекты создаются непосредственно там и никогда не копируются

Ответ №1:

Причина в том, что не выполняется копирование.

В этом случае:

 Check b[2] = {Check(5),Check(4)};
  

Поскольку оба значения являются временными, компилятору разрешено (или, в C 17, принудительно) оптимизировать копирование и вместо этого создавать объекты на месте.

Однако во втором случае:

 Check a[2] = {obj1,obj2};
  

obj1 и obj2 не являются временными, поэтому в этом случае должны иметь место реальные копии.

Ответ №2:

В:

 Check b[2] = {Check(5),Check(4)};
  

этот синтаксис означает, что аргументами конструктора для двух элементов массива являются 5 и 4 . Это не означает, что аргументы являются временными.

Check(5) является выражением prvalue, это не обязательно означает, что материализуется временное значение. Один из способов, которым prvalue может быть «использовано», — это инициализатор для объекта того же типа.

Это поведение изменилось в C 17; до этого концептуально всегда существовало временное, но временное могло быть опущено по усмотрению компилятора.