简体   繁体   English

std::vector 破坏和意外 Memory 泄漏

[英]std::vector Destruction and Unexpected Memory Leak

Consider the following example:考虑以下示例:

#include <vector>
class Foo {
    std::vector<int*> v;
public:
    Foo() {
        this->v.push_back(new int(23));
        this->v.push_back(new int(24));
        this->v.push_back(new int(25));
    }

    ~Foo() {
    }
};

int main() {
    Foo f;
    return 0;
}

When f goes out of scope in main(), f's destructor is called, which should indirectly free fv According to this , the destructor of each element of the vector v should now be called.当 f 在 main() 中超出 scope 时,会调用 f 的析构函数,它应该间接释放 fv 根据这个,现在应该调用向量 v 的每个元素的析构函数。

However, when I run this program in valgrind, I find that the int*'s were not deallocated.然而,当我在 valgrind 中运行这个程序时,我发现 int* 没有被释放。

$ valgrind --leak-check=full ./a.out

What am I missing here?我在这里想念什么?

std::vector<T> does indeed call the destructor of T when it is destroyed. std::vector<T>在销毁时确实调用了T的析构函数。 Here T is int * .这里Tint * The destructor of int * does nothing. int *的析构函数什么都不做。 The storage for the int * itself is freed, but the int s they point to are not. int *本身的存储空间被释放,但它们指向的int s 没有。

Consider:考虑:

int main() {
   int *x = new int(23);
   return 0;
}

This exhibits the same problem;这表现出同样的问题; when x goes out of scope, its destructor is indeed called, and the storage for the pointer that is x is freed, but since the destructor of a pointer is a no-op, the pointed-to int is not freed.x超出 scope 时,它的析构函数确实被调用,并且指针x的存储空间被释放,但由于指针的析构函数是空操作,指向的int没有被释放。

More to the point, vector doesn't know how the int s were allocated.更重要的是, vector不知道int是如何分配的。 They might be allocated by new int , but they could also point to elements inside an array allocated with new int[200] , or they might point to malloc 'd data, or they might point into a mmap 'd buffer, or they might point to struct elements, or two vectors might be pointing to the same int s... etc. vector isn't smart enough to divine what you want done with these, and so it leaves them alone (additionally, giving vector logic to delete pointed-to elements would break vectors of non-pointer elements such as std::vector<int> , as you can't delete an int !)它们可能由new int分配,但它们也可以指向分配有new int[200]的数组中的元素,或者它们可能指向malloc的数据,或者它们可能指向mmap的缓冲区,或者它们可能指向 struct 元素,或者两个向量可能指向同一个int s... 等等vector不够聪明,无法判断你想用这些做什么,所以它不理会它们(此外,提供要删除的vector逻辑指向的元素会破坏非指针元素的向量,例如std::vector<int> ,因为您不能delete int !)

You need to either use a std::vector<int> , or use a smart pointer in conjunction with it, eg std::vector<boost::shared_ptr<int> > .您需要使用std::vector<int> ,或结合使用智能指针,例如std::vector<boost::shared_ptr<int> > Note that using smart pointers may add overhead;请注意,使用智能指针可能会增加开销; with C++0x you should be able to use std::vector<std::unique_ptr<int>> in conjunction with std::move to avoid this overhead.使用 C++0x,您应该能够将std::vector<std::unique_ptr<int>>std::move结合使用以避免这种开销。 Boost also has pointer vectors that free the pointed-to elements as you expected as well. Boost 也有指针向量,可以像你预期的那样释放指向的元素。

The destructor of each element of the vector v should now be called现在应该调用向量v的每个元素的析构函数

Yes: the int* objects stored in the vector are destroyed (which is effectively a no-op).是的:存储在向量中的int*对象被销毁(这实际上是一个无操作)。 The objects pointed to by the pointers in the container are not destroyed.容器中的指针指向的对象不会被销毁。

Consider the following, equally valid program:考虑以下同样有效的程序:

{
    int x;
    std::vector<int*> v;
    v.push_back(&x);
}   // x cannot be delete'd because it isn't dynamically allocated.

You should use a smart pointer, like std::unique_ptr or shared_ptr so that you don't have to worry about the memory management (do not use std::auto_ptr ; it is incompatible with the Standard Library containers because it isn't really copyable).您应该使用智能指针,如std::unique_ptrshared_ptr这样您就不必担心 memory 管理(不要使用std::auto_ptr ;它与标准库容器不兼容,因为它不是真的可复制)。 If you don't use a smart pointer then you need to destroy the dynamically objects yourself;如果您不使用智能指针,那么您需要自己销毁动态对象; doing this correctly is rather difficult.正确地做到这一点相当困难。

Each element of your vector is an int * .矢量的每个元素都是一个int * When an int * is destroyed, the language does not automatically call delete on it.int *被销毁时,语言不会自动对其调用delete In other words, it's the pointer being destroyed, not the pointee.换句话说,被销毁的是指针,而不是指针。

Since you are using the new keyword, the integers are being allocated on the heap rather than the stack.由于您使用的是new关键字,因此整数被分配在堆上而不是堆栈上。 In other words, they are being allocated dynamically.换句话说,它们是动态分配的。 In other words, you need to clean up after it.换句话说,你需要在它之后进行清理。

The "destructor" for a pointer type is to simply delete that pointer.指针类型的“析构函数”是简单地删除该指针。 It does not touch the data which is located at the memory address stored by the pointer.它不接触指针存储的位于 memory 地址的数据。 Consider the following example:考虑以下示例:

int a = 5;
int* i = &a;
if (true)
{
   int* j = i;
} //j goes out of scope, should *i and a be deleted? no.

So you will need to do this in the destructor:所以你需要在析构函数中这样做:

std::vector<int*>::iterator iter;
for (iter = v.begin(); iter != v.end(); iter++)
{
   delete *iter;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM