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

How to avoid memory leak with abstract class pointers

假设我有一个抽象 class(下面示例中的 "Book")和一些派生的 classes("ElectroniBook","CodingBook"下面的例子)。我还想在第三个 class ("Library") 和一些地图中保留书籍矢量以找到它们。我们还假设我需要使用 "addBook" 方法从其他地方创建 "Library",然后在 main 中分配它。

由于 Book 是抽象的,所以我最终需要删除我创建的 "Book" 指针,我想在一些析构函数中执行此操作。尽管如此,每当我尝试使用 delete 时,我都会收到此错误消息

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
}

因为我做了几次"new"添加书籍,所以我需要删除它们。我尝试像我展示的那样在库析构函数中执行此操作,但出现了之前提到的错误。

如果我对你的问题的理解正确,你将释放两倍的内存:

// 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. 确保其他 non-owning 结构,例如我们示例中的 bookmap,永远不会访问内存(即 de-reference 指针)删除

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