为什么调用析构函数
Why is the destructor called?
我写了一个简单的向量类,它重载赋值和加法运算符。该代码将两个矢量相加,并在相加前后打印矢量。令人惊讶的是,析构函数~MyVector()在c=a+b行之后被调用。我看不出为什么会这样,因为对象a、b和c都没有超出范围。你理解调用析构函数的原因吗?
#include<iostream>
#include<cstdlib>
using namespace std;
template<typename T>
class MyVector
{
public:
MyVector(int s)
{
size=s;
a=new T[s];
}
~MyVector()
{
delete[] a;
size=0;
};
void freeVec()
{
cout<<"Calling destructor. a[0]= "<<a[0]<<endl;
if(a!=NULL)
{
free(a);
a=NULL;
}
}
int getSize(void)
{
return size;
}
void setSize(int ss)
{
size=ss;
}
T &operator[](int i)
{
return a[i];
}
MyVector &operator=(MyVector mv)
{
if(this==&mv)
return *this;
for(int i=0;i<mv.getSize();i++)
this->a[i]=mv[i];
this->size=mv.getSize();
return *this;
}
MyVector operator+(MyVector &mv)
{
for(int i=0;i<size;i++)
{
this->a[i]+=mv[i];
}
cout<<endl;
return *this;
}
private:
int size;
T *a;
};
int main(void)
{
MyVector<int> a(3),b(3),c(3);
a[0]=1;a[1]=2;a[2]=3;
b[0]=4;b[1]=5;b[2]=6;
cout<<"initial vector"<<endl;
for(int i=0;i<3;i++)
cout<<a[i]<<" ";
cout<<endl;
for(int i=0;i<3;i++)
cout<<b[i]<<" ";
cout<<endl;
c=a+b;
cout<<"final vectors"<<endl;
for(int i=0;i<3;i++)
cout<<a[i]<<" ";
cout<<endl;
for(int i=0;i<3;i++)
cout<<b[i]<<" ";
cout<<endl;
for(int i=0;i<3;i++)
cout<<c[i]<<" ";
cout<<endl;
cout<<endl;
return 0;
}
您的a + b
返回一个无名称的临时对象,该对象随后被复制到c
(由赋值运算符),然后被销毁。这就是你看到的析构函数调用。
此外,您的赋值运算符通过值接收参数(为什么???),这意味着理论上也可以为此创建另一个副本。您的编译器显然优化了该副本,这就是为什么您只看到一个额外的析构函数调用。
顺便说一句,由于您手动管理对象中分配的内存,因此根据"三条规则"实现复制构造函数也是一个非常好的主意。该类的当前版本(没有复制构造函数)可以很容易地用于构建损坏的代码,特别是因为缺少复制构造函数。事实上,您当前的代码已经损坏,因为它使用编译器提供的复制构造函数来复制类对象。你没有看到任何崩溃的唯一原因是编译器优化了(消除了)大部分副本,可能是因为你运气好。
除此之外,二进制+
的实现会修改存储在*this
对象中的数据(为什么??),这意味着c = a + b
会修改a
。这并不是人们所期望的二进制+
运算符的典型行为。
在您的代码中还有许多其他奇怪的东西。例如,什么是freeVec
,为什么它试图在总是由new[]
分配的内存上使用free
?另外,为什么析构函数将size
设置为0
?这有什么意义?
因为MyVector operator+(MyVector &mv)
创建了一个副本(它应该这样做)。一旦该临时副本存储在c
中,它就会被销毁。
请注意,在operastor+
中修改this
并不是一个好计划。您不希望a
从c = a + b;
变成与c
相同的值。
在c = a + b;
行中,实际上有2个操作。第一个是加法。按照您实现它的方式,a
实际上会增加b
的值。然后在CCD_ 24行中返回CCD_ 23的副本。此副本尚未分配给c
;这是一个无名的暂时。
在赋值调用中,此副本通过值传递,从而创建另一个副本。然而,通过省略副本,我相信第二个副本可能已经优化,因此总共创建了1个副本。因此,赋值运算符的输入是对象的副本。当赋值运算符返回时,该对象将被销毁。
与您的问题有些正交的是,我想指出,您实现运算符的方式存在许多问题。首先,您的+
操作符正在修改与其关联的对象。在c = a + b;
行中,由于函数中的this->a[i]+=mv[i];
行,a
的值被修改,我认为这不是您想要的效果。
其次,在您实现的=
操作符中,行
if(this==&mv)
return *this;
是无用的,因为mv是按值传递的,并且无论如何都不会具有与this
相同的地址。
- 析构函数调用
- 在具有向量的类构造函数中进行析构函数调用
- 从 c++ 中派生类的析构函数调用虚函数
- C++析构函数调用两次,堆栈分配的复合对象
- C++ 在析构函数调用之前删除的动态成员数组
- 析构函数调用c++中的一个向量
- Singleton模式中的手动析构函数调用:调用多次
- 从内部类的析构函数调用虚拟函数
- 与 boost odeint 集成期间的析构函数调用
- 堆栈展开如何与析构函数调用有关?
- C++:优化析构函数调用
- 以逗号分隔的表达式中的析构函数调用
- GCC 9.1 返回 void& 作为显式析构函数调用的结果类型。这是一个错误吗?
- 从C++中的虚拟析构函数调用虚拟方法
- 从指针返回对象时出现意外的析构函数调用
- 使用 decltype 显式析构函数调用
- C++析构函数调用了错误的对象
- 了解虚拟函数和析构函数调用
- 多重继承析构函数调用他自己和父析构函数?c++
- 析构函数调用表单不适当的库