内存泄漏 - STL 集

发布于 2024-08-24 03:04:47 字数 3200 浏览 2 评论 0原文

我正在尝试堵住所有内存泄漏(这是巨大的)。我是STL新手。我有一个班级图书馆,里面有 3 套。我还在库类中使用 new 创建了大量内存,用于向集合添加信息...

我需要取消分配集合吗?如果是这样,怎么办?

这是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()
{


}

另外,我是否正确分配了字符串集?

    #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);

注意:我没有复制构造函数。我不确定我是否需要一个或如何添加一个。我认为我的析构函数也没有被调用。

I am trying to plug up all my memory leaks (which is massive). I am new to STL. I have a class library where I have 3 sets. I am also creating a lot of memory with new in the library class for adding info to the sets...

Do I need to deallocate the sets? If so, how?

Here is the 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();
};

I am not sure what i need to do for the destructor?

Library::~Library()
{


}

also, am I de allocating the stringset right?

    #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;

}

in the library class I am creating a lot of memory, but dont the destructor clean that up?
example:

    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);

Note: I do not have a copy constructor. I am not sure if I even need one or how top add one. I dont think my destructors are getting called either..

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

樱花细雨 2024-08-31 03:04:47

STL 容器不是为保存指针而设计的。

查看 boost 指针容器。这些容器被设计用来保存指针。

#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;

附言。很难准确地判断,但看起来有太多接口返回指针。在 C++ 中实际返回指针(或传递指针)的情况非常罕见。您的接口通常应采用对象/引用或智能指针(通常按此顺序,但取决于情况)。

使用指针应该是最后的手段,因为没有明确指示对象的所有者,因此清理成为问题(从而导致大量内存泄漏)。

STL containers are not designed to hold pointers.

Look at the boost pointer containers. These containers are designed to hold pointers.

#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

The containers hold and own the pointers so they will be deleted when the container goes out of scope. But the beautiful thing about the containers is that you access the objects via references so all the standard algorithms work without any special adapters.

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

PS. Its hard to tell accurately but it looks like too many of your interfaces return pointers. It is very rare in C++ to actually return pointers (or pass pointers around). Your interfaces should usually take objects/references or smart pointers (usually in that order but it depends on the situation).

Working with a pointer should be your last resort as there is no clear indication of the owner of the object and thus cleanup becomes the issue (thus leading to massive memory leaks).

沉鱼一梦 2024-08-31 03:04:47

您需要释放集合中每个元素的内存。容器不会为您执行此操作,也不应该这样做,因为它无法知道它是否拥有该数据 - 它可能只是保存指向其他对象所拥有的对象的指针。

这是一个通用的自由函数,可以释放任何 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();

You need to free the memory for each element of the set. The container will not do that for you, and it shouldn't because it can't know whether it owns that data or not -- it could just be holding pointers to objects owned by something else.

This is a generic free function that will deallocate any STL container.

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();
傾旎 2024-08-31 03:04:47

还没有浏览完您的所有代码,但从前几行看来您正在维护指针集。每当您有一个保存指针的 STL 容器并且您使用 new 将内容放入指针时,您必须使用 delete 来释放这些指针。 STL 不会为你做这些事。事实上,STL 甚至不知道它们是指针。

另一种选择是根本不使用指针,只使用一组对象,而不使用 new 来创建它们。只需在堆栈上创建它们并将它们复制到集合中即可。

haven't gone through all of your code but from the first few lines it seems you're maintaining sets of pointers. Whenever you have an STL container which holds pointers and you're using new to put stuff in the pointers, you must use delete to deallocate these pointers. STL doesn't do that for you. In fact, STL doesn't even know they are pointers.

Another option is to not use pointers at all and have a set of just the objects and not use new to create them. Just create them on the stack and copy them into the set.

冷默言语 2024-08-31 03:04:47

好吧,这可能是一个愚蠢的评论,但是您真的需要将所有内容都堆分配(又名。使用指针和 new 吗?)

您不能只使用普通实例吗? RAII 允许更简单的代码并且没有内存泄漏。

例如:

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();
};

使用这种方法,析构函数必须严格不执行任何操作,并且不会发生内存泄漏。在大多数情况下,可以轻松避免使用指针,而且绝对应该这样做!

Well, this might be a stupid comment, but do you really need to have ALL your stuff heap-allocated (aka. using pointers and new ?)

Can't you just use plain instances ? RAII allows easier code and no memory leak.

For example 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();
};

With this approach, the destructor has to do strictly nothing, and no memory leak. In most cases using pointers can be easily avoided, and definetly should!

妳是的陽光 2024-08-31 03:04:47

查看您在其他问题中发布的一些代码(例如 https://stackoverflow.com/ questions/2376099/c-add-to-stl-set),您的项目存储在多个全局 ItemSet 对象中。这不是一个好的设计 - 它们确实应该是 Library 对象的一部分,因为它们在逻辑上属于该对象。

修复内存泄漏的最佳方法不是处理原始指针 - 要么将智能指针存储在集合中,要么按照 Martin York 的建议使用 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 对象而不是指针,那么您根本不需要析构函数。再次强调,通过原始指针和手动使用删除进行内存管理很容易出错,应该尽可能避免。

Looking at some of the code you posted in other questions (such as https://stackoverflow.com/questions/2376099/c-add-to-stl-set), your items are stored in several global ItemSet objects. This isn't a good design - they really should be part of the Library object, since they logically belong to that.

The best way to fix the memory leaks is not to deal with raw pointers - either store smart pointers in the sets, or use Boost pointer containers as Martin York suggests. Also, your ItemSetMap objects should contain Set objects rather than pointers - there is absolutely no reason to store pointers in them.

If you really must store pointers, then your destructor must walk through each set to delete the contents:

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
}

but this really isn't how you should be doing it, as just about everyone answering your questions has pointed out.

As for the StringSet, you created it with plain new not new[], so you must delete it with plain delete not delete[]. Or, better still, make music a StringSet object rather than a pointer, then you won't need the destructor at all. Once again, memory management through raw pointers and manual use of delete is error prone, and should be avoided if at all possible.

肩上的翅膀 2024-08-31 03:04:47

在析构函数中,您需要迭代包含指针的 stl 集合并删除它们。像这样:

while (!collection.empty()) {
    collection_type::iterator it = collection.begin();
    your_class* p = *it;
    collection.erase(it);
    delete p;
}

In the destructor you need to iterate over your stl collections that contain pointers and delete them. Like this:

while (!collection.empty()) {
    collection_type::iterator it = collection.begin();
    your_class* p = *it;
    collection.erase(it);
    delete p;
}
默嘫て 2024-08-31 03:04:47

正如其他人所指出的,您需要取消分配指针。 set 析构函数通常不会为您执行此操作。否则,如果您希望为您完成此操作,请使用 boost::scoped_ptrstd::tr1::shared_ptr,您可以在其中指定自定义删除器来执行此操作这份工作适合你。

As others have noted, you need to deallocate the pointers. The set destructor normally wouldn't do this for you. Otherwise, if you want this to be done for you, use a boost::scoped_ptr or a std::tr1::shared_ptr where you can specify a custom deleter to do this job for you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文