如何使用抽象类指针避免内存泄漏

How to avoid memory leak with abstract class pointers

本文关键字:内存 泄漏 指针 何使用 抽象类      更新时间:2023-10-16

假设我得到了一个抽象类(在下面的示例中为"Book")和一些派生类(在下面的示例中为"ElectroniBook","CodingBook")。我还想在第三类("图书馆")中保留一个书籍载体,并有一些地图来找到它们。我们还假设我需要使用 "addBook" 方法从其他地方创建"库",然后在 main 中分配它。

由于 Book 是抽象的,我最终需要删除我创建的"Book"指针,我想在某个析构函数中执行此操作。从来没有,每当我尝试使用删除时,我都会收到此错误消息

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

如果我尝试用 shared_pointers 或 unique_pointers 替换原始指针,我会在编译时立即收到错误,告诉我我正在尝试使用已删除的指针。请注意,我使用的是 C++ 11。

下面是一些示例代码:

class Book{
public:
Book(string name, int Npages);
virtual ~Book();
virtual void displayBook() = 0;
private:
string _name;
int _Npages;
}

class ElectronicBook : public Book{
public:
ElectronicBook(string name, int Npages);
~ElectronicBook();
void displayBook() {  //do something 
};
}
class CodingBook : public Book{
public:
CodingBook(string name, int Npages);
~CodingBook();
void displayBook() { // do something  else
};
}

class Library{
public :
Library();
~Library(){
// this doesn't work for me
// for(auto & a : _books)
//    delete a;
//  _books.clear();
// 
//for(int i=0;i<_bookmap.size();++i)
//    delete bookmap.at(i);    
};
void addCodingBook(string name, int Npages){
CodingBook* cb = new CodingBook(name, Npages);
_books.push_back(cb);
_bookmap[name] = cb;
//should I delete anything here?
};
void addEletronicBook(string name, int Npages){
ElectronicBook* eb = new ElectronicBook(name, Npages);
_books.push_back(eb);
_bookmap[name] = eb;
//should I delete anything here?
};
private :
vector<Book*> _books;
map<string, Book*> bookmap;
}

// separeted function
Library createLibrary(){
Library L;
while(...){
//read books from somewhere(file, input or whatever) and 
// addElectronicBook(...) 
// addCodingBook(...)
}
return L;
}

int main(){
Library myLibrary = createLibrary();
// do something with Library
}

由于我做了几次"新"来添加书籍,我需要删除它们。我尝试像我展示的那样在库析构函数中执行此操作,但我得到了之前提到的错误。

如果我正确理解您的问题,您将释放两次相同的内存:

// for(auto & a : _books)
//    delete a;
//  _books.clear();
// 
//for(int i=0;i<_bookmap.size();++i)
//    delete bookmap.at(i); 

_booksbookmap都包含指向相同内存的指针,并且您正在释放它们两次。 使用原始指针时,您必须决定谁是内存的所有者,例如_books,以及谁可以简单地访问内存但不负责清理。 因此,您应该:

  1. 删除一次,所以只使用两个 for 循环中的一个,比如说为了参数_books

  2. 确保其他非拥有结构(例如在我们的示例中bookmap)在删除后永远不会访问内存(即取消引用指针)

建议:放入矢量unique_ptr,使矢量成为所有者,并在地图中放置原始指针以表示地图不拥有。unique_ptr将负责为您清理内存。如果要确定,请在析构函数中添加一些打印语句或在析构函数中放置断点(如果您有调试器)。