2009-06-14 60 views
15

在过去的几天里我很痛苦地学习了很多关于C++编程的知识。
我爱它:)
我知道我应该释放内存 - 现在在我的世界中存在黄金“每个malloc = free”或“每个new = delete”规则,但是我将它们用于相当简单的对象。
矢量呢?无论我在哪里,我都在使用vector.clear(),但这显然是不够的,因为我的内存泄漏很大。
你能指导我如何对待这件事?我应该删除矢量<string>?

*编辑
谢谢,您的意见让我想到了这个应用程序的运算,我将能够完全消除该向量。 :O
对不起 - 我开始解释我在这里的用例,并且发现了我真正需要的东西。就像你每天为18小时的最后3天编码一样:| *编辑2
这很疯狂。通过代码的小改动,我已经将内存使用量从2x130 mb(不断增长)消除为2x 13.5mb,不变的大小。感谢让我以另一种方式思考这个问题。

Btw。这样的自我代码审查得到了一个名字 - 任何人都记得吗当你问任何人(甚至你的母亲或狗)并开始解释你的问题时 - 突然间你自己解决这个5小时的问题,只是试图从另一个角度来看问题,或者试图总结一下它是什么所有关于。我经常发现自己被捕获...

+5

由于您是内存管理的新手,可能您可以解释您是如何知道自己正在获取内存泄漏。测量内存泄漏的一些方法并不能真正反映出发生了什么。 – 2009-06-14 19:49:37

+0

你可能想发布一些你如何使用矢量类的示例代码。例如,你有指向动态创建对象的向量吗? – 2009-06-14 19:57:03

+0

好吧,我只是看到,我的应用程序执行导致越来越多的内存占用。我正在执行相当简单的操作(在两个进程中进行md5哈希,并与mpcih2绑定),对于我的测试,它完全是两千五百万次操作。一个进程发送给其他数据包(字符串),第二个为其计算散列值。在执行结束时,我已经拍摄了两次130 MB。这太正常了。 – IamDeveloper 2009-06-14 19:59:24

回答

19

规则是,当你清除对象的向量时,每个元素的析构函数将被调用。另一方面,如果你有一个指针向量,vector::clear()不会调用delete对他们,你必须自己删除它们。因此,如果你所拥有的只是一个字符串向量,而不是指向字符串的指针,那么你的内存泄漏必然是由其他东西引起的。

+0

这是否适用于一般?如果我有一个具有'std:vector'作为它的一个属性的类,当类被销毁时,C++会调用这个析构函数吗? – 2014-12-05 16:20:37

+4

是的。当一个对象被销毁时,它的所有数据成员的析构函数被调用。但正如我所说,了解你在矢量中存储的内容。如果它是一个对象的矢量,这些对象将与矢量一起被销毁。如果它是一个指针向量,那么你必须自己删除它们。 – Dima 2014-12-05 16:24:39

7

调用v.clear()将销毁v中当前保存的所有对象,但它不会释放内存(假定该向量很快会被再次填充)。

如果你真的想释放内存,这个成语是

vector<string>().swap(v); 

这将创建一个新的(临时)载体,并与v交换其内容。临时向量然后被销毁,释放内存。

+0

现在我看到了背后的意图,但对我来说看起来很尴尬。它会和v.swap一样吗(向量())? – ypnos 2009-06-14 19:55:48

+2

看起来很尴尬,但它是减少'v.capacity()'的惯用方法。你的代码片段不会编译,因为'vector ()'是一个右值,不能绑定到非const引用。 – avakar 2009-06-14 19:58:34

+0

澄清:在a .wap(b)中,a和b不相等。成员交换有一个参数,一个非const引用。你可以调用临时对象的非const成员函数,所以在一个.wap(b)中,a可以是临时的。但是b绑定到非const引用,不能是临时的。 – MSalters 2009-06-15 07:49:57

4

的载体(如所有的标准容器)拥有它里面的对象。
所以它负责销毁它们。

注意:如果vector包含指针,则它拥有指针(而不是指针指向的指针)。所以这些需要删除。但有更简单的方法。

您可以使用智能指针向量。事实上,你应该使用几乎所有形式的智能指针。如果你使用的是指针,你可能仍然像C程序员一样编程。

所以:

std::vector<int> data; // clear is fine. 

std::vector<int*> data1; // Now things need to be deleted. 
// alternative 1: 
std::vector<boost::shared_ptr<int> > data2; // The shared pointer will auto 
              // delete the pointer. 
// alternative 2: 
boost::ptr_vector<int> data3;    // Here the container knows that 
              // it is holding pointers and will 
              // auto de-reference them when you 
              // its members. 

但它听起来像你需要开始思考学习的智能指针。

int* x = new int(5); 
// Do stuff. 
*x = 8; 
delete x; 

// --- Instead use a smart pointer: 
std::auto_ptr<int> x(new int(5)); 
// Do stuff. 
*x = 8; 
// No delete (the auto ptr handles it. 
5

从STL容器删除元素保证调用这些元素的析构函数。然而,如果你有一个pointer-to-T类型的容器,那么你仍然必须自己释放指向内存(在这种情况下,指针的“析构函数”被调用,这是一个无操作)。

如果您不想在此情况下手动管理内存,请考虑使用smart-pointer solutionpointer container

7

你不需要这样做。 std :: string会自行清理,所以字符串不是你的问题。请记住,您没有使用new,因此您不必使用delete

您应该了解RAII - 它使分配和释放更简单。您将以这种方式避免内存泄漏。

1

如果你有一个向量,它超出了范围,向量中的所有对象都被销毁。除非要转储内容并重新使用向量,否则不需要调用clear()。

但是,如果你有机会使用像vector这样的东西,那么被指向的对象的析构函数将不会被调用,因为vector析构函数不会遵循由指针表示的indirections。

所有这一切,你真的确认你有真正的内存泄漏,并且它们是由向量中的数据引起的吗?

0

正如rlbond建议的那样,使用RAII。

绝对不要把新的和删除的调用放到主代码流中。总是尝试将它们放入对象中,以便对象析构函数可以释放需要释放的内容。通过这种方式,您可以避免需要记住调用delete,它使您的代码异常安全(假设您使对象的操作异常安全)。例如,如果您有一个指向STL字符串或C样式字符数组的指针向量,请将其放入一个StringContainer(使用更好的名称)并让StringContainer存放一个向量,并在StringContainer析构函数中运行for循环删除向量中的每个字符串。

您可以将StringContainer内部的矢量设置为公共成员并直接使用它,但它甚至可以更好地设计为使其成为私有或受保护的,并添加一些成员函数来管理字符串* vector。

因此,您的主要C++程序不应该在任何地方看到新的或删除。相反,它应该有很多堆栈分配对象,auto_ptrs和shared_ptrs。