#include <iostream>
using namespace std;
class t{
private:
int * arr;
public:
t() { arr=new int[1]; arr[0]=1;}
t(int x) {arr=new int[1]; arr[0]=x;}
t(const t &);
~t() {cout<<arr[0]<<" de"<<endl; delete [] arr;}
t & operator=(const t & t1){arr[0]=t1.arr[0];return *this;}
void print(){cout<<arr[0]<<endl;}
};
t::t(const t & t1) {arr=new int[1];arr[0]=t1.arr[0];}
int main(){
t b=5;
cout<<"hello"<<endl;
b.print();
b=3;
b.print();
return 0;
}
Почему результат
hello
5
3 de
3
3 de ?
почему "tb = 5;" не вызовет деструктор? как работает "tb = 5"? он создает временный объект (класса t), используя сначала конструктор "t (int x)", затем используйте конструктор копирования "t (const t &)" для создания b? если это так, то почему он не вызывает дескриптор для временного объекта?
почему "tb = 5;" не вызовет деструктор?
Когда вы это сделаете:
t b=5;
вы получаете инициализацию копирования. Семантически вызывается неявный конструктор преобразования t(int)
, а затем создается экземпляр t(const t&)
копии для создания экземпляра b
. Однако компилятору разрешено копировать копию, что и происходит в вашем случае. Объект построен на месте, без необходимости создания копии. Вот почему вы не видите деструкторный вызов. Но вашему классу по-прежнему нужен конструктор копирования для компиляции этого кода: copy elision не является обязательным и не зависит от того, будет ли компилятор компилятора выполнять эликсирование или нет.
Если бы вы сказали
t b(5);
то была бы прямая инициализация, без копирования, и только с одним вызовом конструктора. Для компиляции для вашего класса не потребуется конструктор копирования.
Поскольку у вас нет оператора присваивания, принимающего int
, b = 3;
интерпретируется как
'b.operator=(t(3));'
Это создает временный t
экземпляр и уничтожает его после возвращения задания. То, что печатает первую de
линию. Наконец, в конце main
b
выходит из сферы действия, его деструктор вызывается и печатает вторую строку.
Может быть, небольшой след из вашей программы поможет вам понять, что происходит:
int main(){
t b=5; // as you expected, this call the constructor of your object.
cout<<"hello"<<endl;
b.print(); // as you could see, this call print() and print 5
b=3; // this is where the confusion begins. You didn't provide a way
// from your object to make an assigment from an integer, but you
// provide a way to construct an object from integer. So, your
// compiler will construct a temporary object, with 3 as parameter
// and use this object to do this assignment. Once this is a
// temporary object, it will be destructed at the end of this
// operation. That is why you are getting the message: 3 de
b.print(); // print 3 as expected
return 0; // call the destruct from the object that was assigned before
}
tb=5;
не приводит к вызову деструктора, поэтому поведение не полностью ", как вы ожидали". В этой очень простой строке есть досадные тонкости :-)
tb=5
не вызывает деструктор, а b=3
вызывает его. И ответ tb=5
- конструктор, а b=3
- присваивание.
tb=5;
это не назначение, это инициализация. Он использует конструкторt(int)
, а неoperator=
.