[英][c++]Why is my class destructor called twice?
我有这样的代码,
#include <iostream>
#include <string>
using namespace std;
class Heart {
private:
int bpm;
public:
Heart(int bpm) : bpm(bpm) {}
int getBPM() {
return bpm;
}
};
class Kidney {
private:
double PercentFunction;
public:
Kidney() : PercentFunction(0) {}
Kidney(double pf) : PercentFunction(pf) {}
double getPF() {
return PercentFunction;
}
};
class Person {
private:
string fname, lname;
int age;
Heart h;
Kidney* k;
public:
Person(string fn, string ln, int age, int bpm, double kpf1, double kpf2) : fname(fn), lname(ln), age(age), h(bpm) {
k = new Kidney[2];
k[0] = Kidney(kpf1);
k[1] = Kidney(kpf2);
cout << fname << " " << lname << ", aged " << age << ". Heart BPM : " << bpm <<
". Kidneys' percent function indices: " << k[0].getPF() << " and " << k[1].getPF() << '.' << endl;
}
~Person() {
cout << "A person is dying!" << endl;
delete[] k;
}
};
int main() {
Person p = Person("Jack", "Bowen", 24, 60, 0.99, 0.98);
}
然后我运行我的代码,弹出错误(调试断言失败!)。 您还可以看到析构函数被调用两次。 但是如果我删除delete [] k;
在〜Person中,不会出现此类弹出错误。
在Person构造函数中有动态分配:
k = new Kidney[2];
k[0] = Kidney(kpf1);
k[1] = Kidney(kpf2);
所以我认为我应该删除析构函数中的k。 我的问题是为什么析构函数被调用两次,以及如何解决该错误?
我正在使用VS 2013。
谢谢!
问题如下。 在行中
Person p = Person("Jack", "Bowen", 24, 60, 0.99, 0.98);
您正在复制初始化p
,即您正在创建一个临时文件,然后将其复制到Person p;
。 最后,临时Person("Jack", "Bowen", 24, 60, 0.99, 0.98);
已被破坏,因此Kidney*
指针悬空了,因为您未实现复制构造函数且复制内容较浅(即,指针本身正在复制,而不是其指向的对象)。 并且您的析构函数被调用两次,因为它在临时变量的生命期结束时(在语句的末尾)首先被调用,然后在Person p
在main()
的末尾超出范围时再次被调用。
只要您的类有指针,就实现其复制构造函数和赋值运算符 。 或者更好的方法是使用智能指针,例如std::shared_ptr
,或者更好的标准容器来跟踪其动态内存,例如std::vector/std::list
等。
快速而又肮脏的代码修复程序(但实际上,您将必须实现copy构造函数,因为您将遇到其他所有类型的问题,例如,从函数返回Person
或按值传递Person
时):
Person p("Jack", "Bowen", 24, 60, 0.99, 0.98);
这样可以避免任何临时情况,并使用直接初始化。
PS:在g++
,使用-Weffc++
编译会警告您这些问题,
警告:“类Person”具有指针数据成员[-Weffc ++],但不会覆盖“ Person(const Person&)” [-Weffc ++]或“ operator =(const Person&)” [-Weffc ++]
我不确定VS是否存在这样的编译器标志。
问题是你的线
Person p = Person("Jack", "Bowen", 24, 60, 0.99, 0.98);
这构造了两个对象:一个在=
的右侧,一个在左侧。 由于您没有定义复制构造函数,因此左侧的复制构造函数将简单地将一个相同的指针复制到右侧。 您提到的两个析构函数都是这两个对象, =
左边的一个是导致问题显现的一个。
为了解决这个问题,您可以执行以下操作之一:
正确定义一个复制构造函数,该构造函数将不复制指针,而是分配一个新的指针,复制内部对象,等等。
更好的方法是用现成的类代替指针,该类为您完成这些事情,例如vector
。
如前所述,添加复制构造函数/赋值操作应该可以。 但是,如果您只是想解决此问题,使用指针将很容易。
int main() {
Person *p = new Person("Jack", "Bowen", 24, 60, 0.99, 0.98);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.