[英]C++ destructor won't free properly
我正在嘗試正確釋放公寓類對象,但是valgrind說“無效的釋放,地址...在線程1的堆棧上”。這是代碼:如果您能指出我的錯誤,我將不勝感激。
class Apartment{
public:
enum SquareType {EMPTY, WALL, NUM_SQUARE_TYPES};
class ApartmentException : public std::exception {};
class IllegalArgException : public ApartmentException {};
class OutOfApartmentBoundsException : public ApartmentException {};
int length;
int width;
int price;
SquareType** squares;
Apartment (SquareType** squares, int length, int width, int price);
Apartment (const Apartment& apartment);
Apartment& operator=(const Apartment& apartment);
~Apartment();
};
Apartment::Apartment (SquareType** squares=NULL, int length=0, int width=0, int price=0){
this->price=price;
this->length=length;
this->width=width;
this->squares = new SquareType*[length];
for(int i=0; i<length ; i++){
this->squares[i]= new SquareType[width];
}
this->squares = squares;
for(int i=0; i<length; i++){
for(int j=0; j<width; j++){
this->squares[i][j] = squares[i][j];
}
}
}
Apartment::Apartment (const Apartment& apartment):length(apartment.length),
width(apartment.width),price(apartment.price),squares(apartment.squares){
for(int i=0; i<apartment.length; i++){
for(int j=0; j<apartment.width; j++){
squares[i][j] = apartment.squares[i][j];
}
}
}
Apartment& Apartment::operator=(const Apartment& apartment){
if(this == &apartment){
return *this;
}
for(int i=0;i<length;i++){
delete [] squares[i];
}
delete [] squares;
squares = new SquareType*[apartment.length];
for(int i=0; i<apartment.length ; i++){
squares[i]= new SquareType[apartment.width];
}
for(int i=0; i<apartment.length; i++){
for(int j=0; j<apartment.width; j++){
squares[i][j] = apartment.squares[i][j];
}
}
price=apartment.price;
length=apartment.length;
width=apartment.width;
return *this;
}
Apartment::~Apartment(){
for(int i=0;i<length;i++){
delete [] squares[i];
}
delete [] squares;
}
這是主要的:
int main(){
Apartment::SquareType square1[5]={Apartment::WALL};
Apartment::SquareType square2[5]={Apartment::WALL};
Apartment::SquareType square3[5]={Apartment::WALL};
Apartment::SquareType square4[5]={Apartment::WALL};
Apartment::SquareType* squares[4]={square1,square2,square3,square4};
Apartment::SquareType* Squares[3]={square1,square2,square3};
Apartment ap(squares,4,5,0);
Apartment ap2(Squares,3,5,50);
return 0;
}
這就是valgrind的輸出: valg
復制構造函數必須像在賦值運算符中一樣復制squares
的內容,而不是僅在apartment.squares
分配地址。
錯誤出在復制構造函數中。 您(正確)具有此功能:
this->squares = new SquareType*[length];
但是此后不久,您將擁有以下功能:
this->squares = squares;
導致內存泄漏和潛在的懸空指針。
更廣泛地:
new
進行如此繁重的處理。 相反,您應該使用標准庫的抽象。 std::vector
似乎非常適合您的情況,實際上可以讓您完全消除析構函數。 除了您的Apartment
構造函數覆蓋從new[]
返回的指針的問題之外,您的副本構造函數還應執行賦值運算符中的操作。 相反,您只是分配了指針,而不是復制數據(您在進行淺表復制,而不是深表復制)。
Apartment::Apartment(const Apartment& rhs) : price(rhs.price), length(rhs.length), width(rhs.width), squares(new SquareType*[rhs.length])
{
for(int i=0; i<rhs.length ; i++)
squares[i]= new SquareType[rhs.width];
for(int i=0; i<rhs.length; i++)
{
for(int j=0; j<rhs.width; j++)
squares[i][j] = rhs.squares[i][j];
}
}
一旦有了這個,就不需要您的賦值運算符來重復相同的代碼。 您的賦值運算符所能做的就是:
#include <algorithm>
//...
Apartment& Apartment::operator=(const Apartment& rhs)
{
Apartment temp(rhs);
std::swap(temp.price, price);
std::swap(temp.length, length);
std::swap(temp.width, width);
std::swap(temp.squares, squares);
return *this;
}
這使用了copy / swap
慣用法。
但是總的來說,即使進行了這些更改,也很容易破壞您的代碼。 如果在Apartment
構造函數中將NULL作為squares
傳遞,並且長度和/或寬度大於0怎么辦? 您將從傳入的NULL指針分配給squares
,從而導致未定義的行為。
最好使用諸如std::vector
容器,該容器可以自動知道其大小,而客戶端不必顯式地提供此信息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.