#include <iostream>
using namespace std;
struct Car
{
int size = 4;
int* tires = nullptr;
Car()
{
cout << "ctor" << endl;
tires = new int[size];
}
Car(const Car& car)
{
cout << "copy ctor" << endl;
tires = new int[size];
memcpy(tires, car.tires, size*sizeof(int));
}
Car& operator= (Car& car)
{
cout << "copy assignment operator" << endl;
tires = new int[size];
memcpy(tires, car.tires, size*sizeof(int));
return *this;
}
~Car()
{
cout << "dtor" << endl;
delete tires;
}
};
int main()
{
cout << "starting..." << endl;
Car car1;
car1.tires[0] = 2;
// Car car2(car1); // #1
Car car2 = car1; // #2 I was expecting the assingment operator to be called here
cout << car1.tires[0] << " " << car2.tires[0] << endl;
return 0;
}
Я понимаю, почему конструктор копирования вызывается в #1, но как он вызывается в #2?
Когда size
всегда 4
, вы можете изменить int* tires = nullptr;
на int tires[4];
, тогда вам не нужно new
всю эту память, и вам не нужно менять delete tires;
на delete[] tires;
, потому что вы можете вообще удалить строку.
К вашему сведению -- 1) У вашего operator=
происходит утечка памяти. У вас не получилось delete[]
старая память. 2) Вы использовали неправильную форму delete
в деструкторе. Должно быть delete []
.
Заявление:
Car car2 = car1;
это НЕ задание, как вы думаете. Назначение может происходить только для существующего объекта, а не при создании объекта.
Приведенное выше утверждение на самом деле является инициализацией , а именно Инициализацией копирования:
Синтаксис
T object = other;
(1)...
Эффекты инициализации копирования:
...
В противном случае, если
T
является типом класса, а cv-неквалифицированная версия типаother
являетсяT
или классом, производным отT
, неявные конструкторыT
проверяются, и наилучшее совпадение выбирается путем разрешения перегрузки. Затем этот конструктор вызывается для инициализации объекта....
Итак, в вашем случае компилятор находит, что конструктор копирования совпадает, и обрабатывает оператор так, как если бы вы вместо этого написали Car car2(car1);
.
Вот почему вызывается конструктор копирования.
И создание явного конструктора копирования explicit Car(const Car& car)
, кажется, предотвращает это.
Компилятор C++ вызовет оператор присваивания только для уже существующего объекта, чтобы перезаписать значения этого объекта значениями другого экземпляра.
car car1,car2;
car2=car1;
И он вызовет конструктор копирования в следующих случаях:
если объект инициализируется другим экземпляром.
car car1;
car car2=car1; //This is equivalent to car2(car1);
если объект передается в функцию как нессылочный параметр.
Здесь вы можете увидеть параметр func, где obj2 инициализируется, а не назначается.
void func(car obj2)//not a reference parameter(car& obj2)
{
//
}
car obj1;
func(obj1);
Объект возвращается из функции - я пока не имею представления об этом.
Инициализация — это когда создается новый объект или переменная для хранения значения, а присваивание — это когда для существующего объекта или переменной устанавливается новое значение.
В приведенном выше примере оператора присваивания оба объекта car1
и car2
содержат значение (вероятно, мусор) во время создания, а затем им присваивается новое значение.
Присваивание — это когда вы присваиваете значение переменной после ее создания:
Car car2; car2 = car1;