簡體   English   中英

C ++析構函數無法正確釋放

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM