处理析构函数中的stl容器的取消分配

时间:2013-05-28 17:42:51

标签: c++ memory stl constructor destructor

这是我第一次使用STL,我对如何释放这些容器使用的内存感到困惑。例如:

class X {
    private:
        map<int, int> a;
    public:
        X();
        //some functions
}

现在让我们说我将构造函数定义为:

X::X() {
    for(int i=0; i<10; ++i) {
        map[i]=i;
    }
}

现在我的问题是我应该为这个类编写析构函数,还是默认的C++析构函数将负责释放内存(完全)?

现在考虑修改上面的类

class X {
    private:
        map<int, int*> a;
    public:
        X();
        ~X();
        //some functions
}

现在让我们说我将构造函数定义为:

X::X() {
    for(int i=0; i<10; ++i) {
        int *k= new int;
        map[i]=k;
    }
}

现在我明白了对于这样一个类,我需要编写一个析构函数,因为new分配的内存不能被map容器的默认析构函数破坏(因为它调用了对象的析构函数,在本例中是一个指针)。所以我尝试编写以下析构函数:

X::~X {
    for(int i=0; i<10; ++i) {
        delete(map[i]);
    }
    //to delete the memory occupied by the map.
}

我不知道如何删除map占用的内存。尽管clear函数存在,但它声称将容器的大小降低到0但不一定要释放下面的内存。矢量的情况也是如此(我想STL中的其他容器,但我没有检查过它们。)

任何帮助表示感谢。

5 个答案:

答案 0 :(得分:3)

  

我应该为这个类编写析构函数,还是默认的C ++析构函数会完全解除内存的释放?

是的,它会。所有标准容器都遵循RAII的原则,并管理自己的动态资源。他们将自动释放他们被销毁时分配的任何内存。

  

我不知道如何删除地图占用的内存。

你没有。当且仅当您使用new创建时,您必须删除某些内容。大多数对象都会自动分配和释放内存。

地图本身嵌入在被销毁的X对象中,因此它将被自动销毁,并且一旦析构函数完成,它的内存将与对象一起释放。

地图分配的任何内存都是地图的责任;它会在析构函数中释放它,它会被自动调用。

您只负责删除动态分配的int个对象。由于很难确保正确删除这些,因此应始终使用RAII类型(例如智能指针或地图本身)来管理内存。 (例如,如果使用new引发异常,则构造函数中存在内存泄漏;通过存储对象或智能指针而不是原始指针可以轻松修复。)

答案 1 :(得分:1)

如果忽略您正在处理的容器类型,只需将其视为容器,您会注意到放入容器的任何东西都归拥有该容器的任何人所有。这也意味着由所有者删除该内存。您的方法足以释放您分配的内存。因为map对象本身是一个堆栈分配的对象,所以它的析构函数将被自动调用。

或者,针对此类情况的最佳做法是使用shared_ptr或unique_ptr,而不是原始指针。这些包装类将自动为您释放内存。

map<int shared_ptr<int>> a;

请参阅http://en.cppreference.com/w/cpp/memory

答案 2 :(得分:1)

当销毁STL集合时,将调用所包含对象的相应析构函数。

这意味着如果你有

class YourObject {
  YourObject() { }
  ~YourObject() { }
}

map<int, YourObject> data;

然后调用YourObject的析构函数。

另一方面,如果要存储指向对象的指针,如

map<int, YourObject*> data

然后调用指针的析构,它释放指针本身但不调用指向的构造函数。

解决方案是使用可以保存对象的东西,比如shared_ptr,这是一个特殊的对象,当没有更多的引用时,它会关心调用holded项目对象。

示例:

map<int, shared_ptr<YourObject>>

答案 3 :(得分:0)

简短的回答是,当容器本身被销毁时,容器通常会负责删除其内容。

它通过销毁容器中的对象来实现。因此,如果您想要足够严重,可以通过分配内存(例如,在其ctor中)创建一种管理不当的类型,但不能正确释放它。显然,这应该通过纠正那些对象的设计来修复(例如,添加释放他们拥有的内存的dtor)。或者,您可以通过存储原始指针来获得相同的效果。

同样,您可以创建一个无法正常工作的分配器 - 分配内存但在被要求释放内存时什么都不做。

在每一个案例中,真正的答案是“就是不要那样做”。

答案 4 :(得分:0)

如果你必须写一个析构函数(或cctor或op =),它表明你可能做错了什么。如果你这样做是为了更有可能解除分配资源。

例外是资源的RAII处理程序,它什么都不做。

在常规课程中,您使用适当的成员和基类,因此您的dtor没有自己的工作。

STL课程都处理自己,所以有了地图你没有义务。除非你用分配内存的哑指针或类似的东西填充它 - 第一次观察开始。

你的第二个X :: X()示例在很多方面都被破坏了,如果在第5次抛出异常,你会泄漏第4个。如果你想手动处理这种情况,你最终会得到一堆代码。
如果你使用一个合适的智能东西,比如unique_ptr或shared_ptr而不是int *,就可以避免这种情况。