Я пытаюсь включить все свои утечки памяти (который является крупным). Я плохо знаком с 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);
Примечание: У меня нет конструктора копии. Я не уверен, нужно ли мне даже один или как вершина добавляет тот. Я не думаю, что мои деструкторы становятся названными также..
Вам необходимо освободить память для каждого элемента набора. Контейнер не сделает этого за вас, и не должен, потому что он не может знать, владеет ли он этими данными или нет - он может просто содержать указатели на объекты, принадлежащие чему-то другому.
Это общая бесплатная функция, которая освобождает любой контейнер 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();
не просмотрел весь ваш код, но из первых нескольких строк кажется, что вы поддерживаете наборы указателей. Если у вас есть контейнер STL, который содержит указатели, и вы используете new
, чтобы поместить материал в указатели, вы должны использовать delete, чтобы деаллоцировать эти указатели. STL не делает этого за вас. На самом деле, STL даже не знает, что это указатели.
Другой вариант - вообще не использовать указатели, иметь набор только объектов и не использовать new
для их создания. Просто создайте их на стеке и скопируйте в набор.
Что ж, это может быть глупый комментарий, но действительно ли вам нужно, чтобы ВСЕ ваши материалы были размещены в куче (то есть с использованием указателей и 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();
};
При таком подходе деструктор не должен делать ничего, кроме утечки памяти. В большинстве случаев использования указателей можно легко избежать, и это определенно следует!
Если посмотреть на код, который вы разместили в других вопросах (например, 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
подвержено ошибкам, и этого следует избегать, если это вообще возможно.
В деструкторе вам нужно перебрать ваши коллекции stl, содержащие указатели, и удалить их. Примерно так:
while (!collection.empty()) {
collection_type::iterator it = collection.begin();
your_class* p = *it;
collection.erase(it);
delete p;
}
Как уже отмечали другие, вам нужно деаллоцировать указатели. Деструктор set
обычно не делает этого за вас. В противном случае, если вы хотите, чтобы это было сделано за вас, используйте boost::scoped_ptr
или std::tr1::shared_ptr
, где вы можете указать пользовательский деаллокатор, который сделает эту работу за вас.
Контейнеры 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 ++ очень редко действительно возвращаются указатели (или передаются указатели). Ваши интерфейсы обычно должны принимать объекты / ссылки или интеллектуальные указатели (обычно в таком порядке, но это зависит от ситуации).
Работа с указателем должна быть вашим последним средством, поскольку нет четкого указания владельца объекта, и поэтому очистка становится проблемой (что приводит к массовым утечкам памяти).