[英][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.