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
习语。
但总的来说,即使有这些更改,也很容易破坏代码。如果NULL在Apartment
构造函数中作为squares
传递,并且长度和/或宽度大于0,该怎么办?您将从传入的NULL指针分配给squares
,从而导致未定义的行为。
如果您使用std::vector
这样的容器,它会自动知道它们的大小,而客户端不必显式地向您提供这些信息,那会更好。
相关文章:
- 调用析构函数以释放动态分配的内存
- std::unordered_map析构函数不释放内存?
- 如何在 c++ 中的析构函数中正确释放合并 LL 的内存?
- 使用析构函数释放链表
- C++ 在不释放内存的情况下调用析构函数
- C++ - 析构函数只是释放内存还是实际删除对象
- 为什么要在释放分配给该对象的内存之前调用该对象的默认析构函数?
- 如何释放C++异常类析构函数中的变量
- 通过复制将对象传递给 CUDA 内核会调用其析构函数并过早释放内存
- 为什么析构函数不释放数组内存?
- C++析构函数以释放内存
- C++析构函数无法正确释放
- SDL在析构函数上释放曲面失败
- 需要析构函数来释放内存空间,即使所有项目都已弹出
- 类析构函数和指针释放
- 在析构函数c++中释放多个缓冲区
- 释放用户定义表达式析构函数中的动态内存
- 调用析构函数以释放C++运算符中的内存的正确方法是什么
- boost::lockfree::队列似乎没有释放内存,尽管每个集合对象上的析构函数都被调用
- 释放析构函数上的堆