Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 内存泄漏-STL集_C++_Stl_Set_Memory Leaks - Fatal编程技术网

C++ 内存泄漏-STL集

C++ 内存泄漏-STL集,c++,stl,set,memory-leaks,C++,Stl,Set,Memory Leaks,我正试图堵住我所有的内存泄漏(这是巨大的)。我是STL的新手。我有一个类库,里面有3套。我还在library类中创建了大量内存,用于向集合中添加信息 我需要取消分配集合吗?如果是,怎么做 这是图书馆 #pragma once #include <ostream> #include <map> #include <set> #include <string> #include "Item.h" using namespace std;

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

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

这是图书馆

    #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();
};
另外,我是否正确地取消了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
在library类中,我创建了大量内存,但析构函数不清理这些内存吗? 例如:


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

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

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

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

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

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

您需要为集合的每个元素释放内存。容器不会为您这样做,它不应该这样做,因为它不知道自己是否拥有该数据——它可能只是持有指向其他对象的指针

这是一个通用的免费函数,将释放任何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();
模板
无效解除分配容器(T&c)
{
for(typename T::iterator i=c.begin();i!=c.end();++i)
删除*i;
}
//用法
设置我的设置;
解除分配\u容器(我的\u集);
我的_set.clear();

好吧,这可能是一个愚蠢的评论,但您真的需要分配所有的东西堆(即使用指针和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();
};
使用名称空间std;
排版项目集;
typedef映射ItemMap;
typedef映射ItemSetMap;
类库
{
公众:
//一般功能
void addKeywordForItem(常量项和项、常量字符串和关键字);
ItemSet itemsForKeyword(常量字符串和关键字)常量;
无效打印项(ostream&out、常量项和项)常量;
//图书相关功能
项目地址簿(常量字符串和标题、常量字符串和作者、int nPages);
ItemSet booksByAuthor(常量字符串和作者)常量;
ItemSet books()常量;
//音乐相关功能
项目ADDMUSICD(常量字符串和标题、常量字符串和带、int NSNGS);
void addBandMember(常量项和音乐ccd、常量字符串和成员);
项目集musicByBand(常量字符串和乐队)常量;
项目集音乐符号(常量字符串和音乐家)常量;
ItemSet musicCDs()常量;
//电影相关功能
项目addMovieDVD(常量字符串和标题、常量字符串和导演、内部nScenes);
void addCastMember(常量项和电影、常量字符串和成员);
ItemSet moviesByDirector(常量字符串和director)常量;
ItemSet moviesByActor(常量字符串和演员)常量;
ItemSet movies()常量;
~Library();
};

使用这种方法,析构函数完全不需要做任何事情,也不需要内存泄漏。在大多数情况下,使用指针可以很容易地避免,而且绝对应该避免

正如其他人所指出的,您需要取消分配指针。
set
析构函数通常不会为您执行此操作。否则,如果您希望为您完成此操作,请使用
boost::scoped_ptr
std::tr1::shared_ptr
,其中您可以指定一个自定义删除程序来为您执行此操作。

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

#include <boost/ptr_container/ptr_set.hpp>
#include <boost/ptr_container/ptr_map.hpp>
看看boost指针容器。这些容器设计用于容纳指针

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

容器持有并拥有指针,因此当容器超出范围时,指针将被删除。但是容器的美妙之处在于,您可以通过引用访问对象,因此所有标准算法都可以在没有任何特殊适配器的情况下工作

typedef boost::ptr_set<Item>              ItemSet;
typedef boost::ptr_map<string,Item>       ItemMap;
typedef boost::ptr_map<string,ItemSet>    ItemSetMap;
typedef boost::ptr_set ItemSet;
typedef boost::ptr_映射ItemMap;
typedef boost::ptr_映射ItemSetMap;
注:很难准确地说出来,但它看起来像是太多的接口返回指针。C++中非常难得地返回指针(或传递指针)。您的接口通常应该采用对象/引用或智能指针(通常按照该顺序,但这取决于具体情况)


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

查看您在其他问题(例如)中发布的一些代码,您的项目存储在多个全局
项目集
对象中。这不是一个好的设计-它们实际上应该是
对象的一部分,因为它们在逻辑上属于该对象

修复内存泄漏的最佳方法不是处理原始指针——要么在集合中存储智能指针,要么按照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
delete[]
删除它。或者,更好的做法是将
music
制作成
StringSet
对象
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
}