一个关于析构函数的奇怪现象

时间:2022-09-11 12:37:25
今天在vc上练习,发现一个奇怪的现象,

#include <iostream>
using namespace std;

class ra{
public:
ra(int temp = 0);
ra(const ra& c);
friend const ra operator*(const ra& c, const ra& d);
//~ra() { cout<<"destructor"<<endl;}
private:
int a;
};

ra::ra(int temp)
{
a = temp;
cout<<"constructor()  "<<a<<endl;
}

ra::ra(const ra& c)
{
a = c.a;
cout<<"copy constructor()  "<<a<<endl;
}

const ra operator*(const ra& c,const ra& d)
{
return ra(c.a*d.a);
}

void main()
{
ra c(5);
ra d(6);
ra e = c*d;
return;
}
当没有析构函数时候,输出结果为:
constructor()  5
constructor()  6
constructor()  30
copy constructor()  30
copy constructor()  30

当有析构函数的时候,输出结果为:
constructor()  5
constructor()  6
constructor()  30
destructor
destructor
destructor


各位大虾帮帮忙解释为什么会有这种现象?


12 个解决方案

#1


正常现象啊,注意 c*d会产生临时变量的

#2


其实不是正常现象,LZ可以尝试在不同的编译器上做下实验,

#3


当没有析构函数时候,输出结果为: 
constructor()     5  //ra   c(5); 构造了一个对象
constructor()     6  //ra   d(6); 构造了一个对象
constructor()     30 //return   ra(c.a*d.a); 也生成一个对象。
copy   constructor()     30 //由于const   ra返回的不是一个引用,故生成临时对象,调用Copy构造函数
copy   constructor()     30 //ra   e   =   c*d; 再次调用Copy构造函数

#4


当有析构函数的时候,输出结果为: 
constructor()     5 
constructor()     6 
constructor()     30 
destructor 
destructor 
destructor 
////////////////////////////////
上面的结果可能是编译器总是造成的。

#5


在 vs2005 中:
无析构的结果:

constructor()     5 
constructor()     6 
constructor()     30 
 


有析构的结果:
constructor()     5 
constructor()     6 
constructor()     30 
destructor 
destructor 
destructor 

#6


[size=11px]疑问在于:
为什么自己写了析构函数,本该有的调用拷贝构造函数的地方却没有调用呢???
用默认的析构函数才有调用拷贝构造函数呢??
[/size]


to  lihao21:
你的解释是不对的
当没有析构函数时候,输出结果为:   
constructor()        5     //ra       c(5);   构造了一个对象 
constructor()        6     //ra       d(6);   构造了一个对象 
constructor()        30   //return       ra(c.a*d.a);   也生成一个对象。 
copy   constructor()      30   //由于const       ra返回的不是一个引用,故生成临时对象,调用Copy构造函数
????????????这里编译器会执行。。。返回值优化。。。,不会再调用拷贝构造函数了,再执行 ra(c.a*d.a)时就直接把对象创建在外部返回值的内存单元。
copy   constructor()      30   //ra       e       =       c*d;   再次调用Copy构造函数

#7


没有调用copy constructor的原因确实是返回值优化.
而destructor被一些编译器用作是否执行返回值优化的标志.如果用户定义了destructor,编译器会认为copy constructor的代价太高(定义destructor一般是为了解决资源的释放问题,那么copy constructor必然需要分配资源),从而执行返回值优化.

当然,这依赖于编译器的策略,各编译器行为可以不一样.

#8


你没有重载 void operator = (ra& a);函数.return   ra(c.a*d.a); 实际上系统会实例化一个隐含的实例,而且调试也追踪不到.

#9


楼主用的VC2046吧 我在VC6 2003下试都没有这个结果
copy   constructor()     30 
copy   constructor()     30 

#10


copy       constructor()             30       //由于const               ra返回的不是一个引用,故生成临时对象,调用Copy构造函数 
????????????这里编译器会执行。。。返回值优化。。。,不会再调用拷贝构造函数了,再执行   ra(c.a*d.a)时就直接把对象创建在外部返回值的内存单元。 
************************************************
那为何会在这里调用copy   constructor??

#11


编译器优化?

#12


lihao21::
constructor()           5     //ra       c(5);   构造了一个对象 
constructor()           6     //ra       d(6);   构造了一个对象 
constructor()           30   //return       ra(c.a*d.a);   也生成一个对象。 
copy       constructor()           30   //由于const       ra返回的不是一个引用,故生成临时对象,调用Copy构造函数 
copy       constructor()           30   //ra       e       =       c*d;   再次调用Copy构造函数

关于第一个拷贝构造函数的调用我没理解啊。如果按你说的生成一个临时对象的话,应该调用的是构造函数啊。怎么会是拷贝构造函数呢?

#1


正常现象啊,注意 c*d会产生临时变量的

#2


其实不是正常现象,LZ可以尝试在不同的编译器上做下实验,

#3


当没有析构函数时候,输出结果为: 
constructor()     5  //ra   c(5); 构造了一个对象
constructor()     6  //ra   d(6); 构造了一个对象
constructor()     30 //return   ra(c.a*d.a); 也生成一个对象。
copy   constructor()     30 //由于const   ra返回的不是一个引用,故生成临时对象,调用Copy构造函数
copy   constructor()     30 //ra   e   =   c*d; 再次调用Copy构造函数

#4


当有析构函数的时候,输出结果为: 
constructor()     5 
constructor()     6 
constructor()     30 
destructor 
destructor 
destructor 
////////////////////////////////
上面的结果可能是编译器总是造成的。

#5


在 vs2005 中:
无析构的结果:

constructor()     5 
constructor()     6 
constructor()     30 
 


有析构的结果:
constructor()     5 
constructor()     6 
constructor()     30 
destructor 
destructor 
destructor 

#6


[size=11px]疑问在于:
为什么自己写了析构函数,本该有的调用拷贝构造函数的地方却没有调用呢???
用默认的析构函数才有调用拷贝构造函数呢??
[/size]


to  lihao21:
你的解释是不对的
当没有析构函数时候,输出结果为:   
constructor()        5     //ra       c(5);   构造了一个对象 
constructor()        6     //ra       d(6);   构造了一个对象 
constructor()        30   //return       ra(c.a*d.a);   也生成一个对象。 
copy   constructor()      30   //由于const       ra返回的不是一个引用,故生成临时对象,调用Copy构造函数
????????????这里编译器会执行。。。返回值优化。。。,不会再调用拷贝构造函数了,再执行 ra(c.a*d.a)时就直接把对象创建在外部返回值的内存单元。
copy   constructor()      30   //ra       e       =       c*d;   再次调用Copy构造函数

#7


没有调用copy constructor的原因确实是返回值优化.
而destructor被一些编译器用作是否执行返回值优化的标志.如果用户定义了destructor,编译器会认为copy constructor的代价太高(定义destructor一般是为了解决资源的释放问题,那么copy constructor必然需要分配资源),从而执行返回值优化.

当然,这依赖于编译器的策略,各编译器行为可以不一样.

#8


你没有重载 void operator = (ra& a);函数.return   ra(c.a*d.a); 实际上系统会实例化一个隐含的实例,而且调试也追踪不到.

#9


楼主用的VC2046吧 我在VC6 2003下试都没有这个结果
copy   constructor()     30 
copy   constructor()     30 

#10


copy       constructor()             30       //由于const               ra返回的不是一个引用,故生成临时对象,调用Copy构造函数 
????????????这里编译器会执行。。。返回值优化。。。,不会再调用拷贝构造函数了,再执行   ra(c.a*d.a)时就直接把对象创建在外部返回值的内存单元。 
************************************************
那为何会在这里调用copy   constructor??

#11


编译器优化?

#12


lihao21::
constructor()           5     //ra       c(5);   构造了一个对象 
constructor()           6     //ra       d(6);   构造了一个对象 
constructor()           30   //return       ra(c.a*d.a);   也生成一个对象。 
copy       constructor()           30   //由于const       ra返回的不是一个引用,故生成临时对象,调用Copy构造函数 
copy       constructor()           30   //ra       e       =       c*d;   再次调用Copy构造函数

关于第一个拷贝构造函数的调用我没理解啊。如果按你说的生成一个临时对象的话,应该调用的是构造函数啊。怎么会是拷贝构造函数呢?