Утечки памяти - наборы STL

Я пытаюсь включить все свои утечки памяти (который является крупным). Я плохо знаком с STL. У меня есть библиотека классов, где у меня есть 3 набора. Я также создаю большую память с новым в классе библиотеки для добавления информации к наборам...

Я должен освободить наборы? Если так, как?

Вот library.h

    #pragma once

#include <ostream>
#include <map>
#include <set>
#include <string>
#include "Item.h"

using namespace std;

typedef set<Item*>              ItemSet;
typedef map<string,Item*>       ItemMap;
typedef map<string,ItemSet*>    ItemSetMap;

class Library
{

public:
    // general functions

    void addKeywordForItem(const Item* const item, const string& keyword);
    const ItemSet* itemsForKeyword(const string& keyword) const;
    void printItem(ostream& out, const Item* const item) const;

    // book-related functions

    const Item* addBook(const string& title, const string& author, int const nPages);
    const ItemSet* booksByAuthor(const string& author) const;
    const ItemSet* books() const;

    // music-related functions

    const Item* addMusicCD(const string& title, const string& band, const int nSongs);
    void addBandMember(const Item* const musicCD, const string& member);
    const ItemSet* musicByBand(const string& band) const;
    const ItemSet* musicByMusician(const string& musician) const;
    const ItemSet* musicCDs() const;

    // movie-related functions

    const Item* addMovieDVD(const string& title, const string& director, const int nScenes);
    void addCastMember(const Item* const movie, const string& member);
    const ItemSet* moviesByDirector(const string& director) const;
    const ItemSet* moviesByActor(const string& actor) const;
    const ItemSet* movies() const;
    ~Library();
};

Я не уверен, что я должен сделать для деструктора?

Library::~Library()
{


}

также, я - de выделение stringset права?

    #ifndef CD_H
#define CD_H
#pragma once
#include "item.h"
#include <set>


typedef set<string> StringSet;


class CD : public Item
{
public:

    CD(const string& theTitle, const string& theBand, const int snumber);
    void addBandMember(const string& member);
    const int getNumber() const;
    const StringSet* getMusician() const;
    const string getBand() const;
    virtual void print(ostream& out) const;
    string printmusicians(const StringSet* musicians) const;

    ~CD();


private:

    string band;
    StringSet* music;

    string title;
    int number;

};

ostream& operator<<(ostream& out, const CD* cd);

#endif

cd.cpp

    #include "CD.h"

using namespace std;

CD::CD(const string& theTitle, const string& theBand, const int snumber)
: Item(theTitle), band(theBand),number(snumber), music(new StringSet)
{



}

CD::~CD()
{

    delete []music;

}

в классе библиотеки я создаю большую память, но разве деструктор не очищает это? пример:

    const Item* Library::addBook(const string& title, const string& author, const int nPages)
{

    ItemSet* obj = new ItemSet();
    Book* item = new Book(title,author,nPages);
    allBooks.insert(item); // add to set of all books
    obj->insert(item);

Примечание: У меня нет конструктора копии. Я не уверен, нужно ли мне даже один или как вершина добавляет тот. Я не думаю, что мои деструкторы становятся названными также..

7
задан Peter Alexander 7 March 2010 в 00:01
поделиться

7 ответов

Вам необходимо освободить память для каждого элемента набора. Контейнер не сделает этого за вас, и не должен, потому что он не может знать, владеет ли он этими данными или нет - он может просто содержать указатели на объекты, принадлежащие чему-то другому.

Это общая бесплатная функция, которая освобождает любой контейнер STL.

template <typename T>
void deallocate_container(T& c)
{
  for (typename T::iterator i = c.begin(); i != c.end(); ++i)
    delete *i;
}

// Usage
set<SomeType*> my_set;
deallocate_container(my_set);
my_set.clear();
3
ответ дан 7 December 2019 в 01:19
поделиться

не просмотрел весь ваш код, но из первых нескольких строк кажется, что вы поддерживаете наборы указателей. Если у вас есть контейнер STL, который содержит указатели, и вы используете new, чтобы поместить материал в указатели, вы должны использовать delete, чтобы деаллоцировать эти указатели. STL не делает этого за вас. На самом деле, STL даже не знает, что это указатели.

Другой вариант - вообще не использовать указатели, иметь набор только объектов и не использовать new для их создания. Просто создайте их на стеке и скопируйте в набор.

1
ответ дан 7 December 2019 в 01:19
поделиться

Что ж, это может быть глупый комментарий, но действительно ли вам нужно, чтобы ВСЕ ваши материалы были размещены в куче (то есть с использованием указателей и new?)

Не могу вы просто используете простые экземпляры? RAII позволяет упростить код и избежать утечки памяти.

Например, have:

using namespace std;

typedef set<Item>              ItemSet;
typedef map<string,Item>       ItemMap;
typedef map<string,ItemSet>    ItemSetMap;

class Library
{

public:
    // general functions

    void addKeywordForItem(const Item & item, const string& keyword);
    ItemSet itemsForKeyword(const string& keyword) const;
    void printItem(ostream& out, const Item & item) const;

    // book-related functions

    Item addBook(const string& title, const string& author, int nPages);
    ItemSet booksByAuthor(const string& author) const;
    ItemSet books() const;

    // music-related functions

    Item addMusicCD(const string& title, const string& band, int nSongs);
    void addBandMember(const Item & musicCD, const string& member);
    ItemSet musicByBand(const string& band) const;
    ItemSet musicByMusician(const string& musician) const;
    ItemSet musicCDs() const;

    // movie-related functions

    Item addMovieDVD(const string& title, const string& director, int nScenes);
    void addCastMember(const Item & movie, const string& member);
    ItemSet moviesByDirector(const string& director) const;
    ItemSet moviesByActor(const string& actor) const;
    ItemSet movies() const;
    ~Library();
};

При таком подходе деструктор не должен делать ничего, кроме утечки памяти. В большинстве случаев использования указателей можно легко избежать, и это определенно следует!

1
ответ дан 7 December 2019 в 01:19
поделиться

Если посмотреть на код, который вы разместили в других вопросах (например, https://stackoverflow.com/questions/2376099/c-add-to-stl-set ), ваши элементы сохранены. в нескольких глобальных объектах ItemSet . Это плохой дизайн - они действительно должны быть частью объекта Library , поскольку логически принадлежат ему.

Лучший способ исправить утечки памяти - не иметь дело с необработанными указателями - либо хранить интеллектуальные указатели в наборах, либо использовать контейнеры указателей Boost, как предлагает Мартин Йорк. Кроме того, ваши объекты ItemSetMap должны содержать объекты Set , а не указатели - нет абсолютно никаких причин хранить в них указатели.

Если вам действительно нужно хранить указатели, тогда ваш деструктор должен пройти через каждый набор, чтобы удалить содержимое:

void Purge(ItemSet &set)
{
    for (ItemSet::iterator it = set.begin(); it != set.end(); ++it)
        delete *it;
    set.clear(); // since we won't actually be destroying the container
}

void Purge(ItemSetMap &map)
{
    for (ItemSetMap::iterator it = map.begin(); it != map.end(); ++it)
        delete it->second;
    map.clear();
}

Library::~Library()
{
    Purge(allBooks);
    Purge(allCDs);
    // and so on and so forth
}

но на самом деле это не то, как вы должны это делать, как указали почти все, отвечая на ваши вопросы.

Что касается StringSet , вы создали его с помощью простого new не new [] , поэтому вы должны удалить его простым delete ] не удалить [] . Или, что еще лучше, сделайте music объектом StringSet , а не указателем, тогда деструктор вам вообще не понадобится. Еще раз, управление памятью с помощью необработанных указателей и ручное использование delete подвержено ошибкам, и этого следует избегать, если это вообще возможно.

1
ответ дан 7 December 2019 в 01:19
поделиться

В деструкторе вам нужно перебрать ваши коллекции stl, содержащие указатели, и удалить их. Примерно так:

while (!collection.empty()) {
    collection_type::iterator it = collection.begin();
    your_class* p = *it;
    collection.erase(it);
    delete p;
}
0
ответ дан 7 December 2019 в 01:19
поделиться

Как уже отмечали другие, вам нужно деаллоцировать указатели. Деструктор set обычно не делает этого за вас. В противном случае, если вы хотите, чтобы это было сделано за вас, используйте boost::scoped_ptr или std::tr1::shared_ptr, где вы можете указать пользовательский деаллокатор, который сделает эту работу за вас.

0
ответ дан 7 December 2019 в 01:19
поделиться

Контейнеры STL не предназначены для хранения указателей.

Посмотрите на контейнеры указателя ускорения. Эти контейнеры предназначены для хранения указателей.

#include <boost/ptr_container/ptr_set.hpp>
#include <boost/ptr_container/ptr_map.hpp>

http://www.boost.org/doc/libs/1_42_0/libs/ptr_container/doc/ptr_set.html

Контейнеры содержат указатели и владеют ими, поэтому они будут удалены, когда контейнер выйдет за пределы области видимости. . Но самое прекрасное в контейнерах то, что вы обращаетесь к объектам через ссылки, поэтому все стандартные алгоритмы работают без каких-либо специальных адаптеров.

typedef boost::ptr_set<Item>              ItemSet;
typedef boost::ptr_map<string,Item>       ItemMap;
typedef boost::ptr_map<string,ItemSet>    ItemSetMap;

PS. Трудно сказать точно, но похоже, что слишком многие из ваших интерфейсов возвращают указатели. В C ++ очень редко действительно возвращаются указатели (или передаются указатели). Ваши интерфейсы обычно должны принимать объекты / ссылки или интеллектуальные указатели (обычно в таком порядке, но это зависит от ситуации).

Работа с указателем должна быть вашим последним средством, поскольку нет четкого указания владельца объекта, и поэтому очистка становится проблемой (что приводит к массовым утечкам памяти).

4
ответ дан 7 December 2019 в 01:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: