C ++析构函数不能正常释放

时间:2016-06-05 07:04:56

标签: c++ class valgrind destructor

我试图正确地释放一个公寓类对象,但是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

3 个答案:

答案 0 :(得分:0)

您的复制构造函数必须像在赋值运算符中一样复制squares的内容,而不是仅仅在apartment.squares中分配地址。

答案 1 :(得分:0)

错误在于复制构造函数。你(正确地)有这个:

    this->squares = new SquareType*[length];

然后你很快就有了这个:

    this->squares = squares;

导致内存泄漏并且可能是悬空指针。

更广泛地说:

  • 你不应该在new中如此重视。相反,你应该使用标准库的抽象; std::vector似乎非常适合您的情况,事实上可以让您完全消除析构函数。
  • 你应该看看&#34; What is the copy-and-swap idiom?&#34 ;;这是使这些核心功能更简单,更健壮的一种方法。

答案 2 :(得分:0)

除了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成语。

但总的来说,即使使用这些更改,也很容易破坏您的代码。如果在squares构造函数中将NULL作为Apartment传递,并且长度和/或宽度大于0,该怎么办?您将从传入的NULL指针分配给squares,从而导致未定义的行为。

如果您使用std::vector之类的容器自动了解其大小,而客户端不必明确地向您提供此信息,那会更好。