Как избежать утечки памяти с помощью абстрактных указателей классов - PullRequest
0 голосов
/ 20 июня 2019

Давайте предположим, что я получил абстрактный класс («Книга» в приведенном ниже примере) и некоторые производные классы («Электронная книга», «CodingBook» в приведенном ниже примере).Я также хочу сохранить вектор книг в третьем классе («Библиотека») и несколько карт, чтобы найти их.Давайте также предположим, что мне нужно создать «Библиотеку» из другого места, используя метод «addBook», а затем назначить ее в основном.

Поскольку 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
}

Поскольку я несколько раз делал "новые" для добавления книг, мне нужно их удалить.Я попытался сделать это в деструкторе Библиотеки, как я показал, но я получил ошибку, упомянутую ранее.

1 Ответ

3 голосов
/ 20 июня 2019

Если я правильно понимаю вашу проблему, вы освобождаете два раза одну и ту же память:

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

Оба _books и bookmap содержат указатели, которые указывают на одни и те же области памяти, и вы освобождаетеих дважды.При работе с необработанными указателями вы должны решить, кто является владельцем памяти, например, _books, а кто просто имеет доступ к памяти, но не отвечает за очистку.Итак, вы должны:

  1. удалить только один раз, поэтому используйте только один из двух циклов for, скажем, ради аргумента _books

  2. убедитесь, что другие несобственные структуры, скажем, bookmap в нашем примере, никогда не обращаются к памяти (т.е. отменяют ссылку на указатель) после удаления

Предложение: вставьте вектор unique_ptr, чтобы вектор являлся владельцем, и поместите необработанные указатели на карту, чтобы указать, что карта не принадлежит.unique_ptr позаботится о том, чтобы очистить память для вас.Если вы хотите быть уверенным, добавьте некоторые операторы печати или поместите точки останова в деструкторы, если у вас есть отладчик.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...