这是我第一次使用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中的其他容器,但我没有检查过它们。)
任何帮助表示感谢。
答案 0 :(得分:3)
我应该为这个类编写析构函数,还是默认的C ++析构函数会完全解除内存的释放?
是的,它会。所有标准容器都遵循RAII的原则,并管理自己的动态资源。他们将自动释放他们被销毁时分配的任何内存。
我不知道如何删除地图占用的内存。
你没有。当且仅当您使用new
创建时,您必须删除某些内容。大多数对象都会自动分配和释放内存。
地图本身嵌入在被销毁的X
对象中,因此它将被自动销毁,并且一旦析构函数完成,它的内存将与对象一起释放。
地图分配的任何内存都是地图的责任;它会在析构函数中释放它,它会被自动调用。
您只负责删除动态分配的int
个对象。由于很难确保正确删除这些,因此应始终使用RAII类型(例如智能指针或地图本身)来管理内存。 (例如,如果使用new
引发异常,则构造函数中存在内存泄漏;通过存储对象或智能指针而不是原始指针可以轻松修复。)
答案 1 :(得分:1)
如果忽略您正在处理的容器类型,只需将其视为容器,您会注意到放入容器的任何东西都归拥有该容器的任何人所有。这也意味着由所有者删除该内存。您的方法足以释放您分配的内存。因为map对象本身是一个堆栈分配的对象,所以它的析构函数将被自动调用。
或者,针对此类情况的最佳做法是使用shared_ptr或unique_ptr,而不是原始指针。这些包装类将自动为您释放内存。
map<int shared_ptr<int>> a;
答案 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 *,就可以避免这种情况。