泄漏是什么意思?

时间:2012-12-13 09:07:53

标签: c++ pointers vector

我只知道内存泄漏的正式含义,如果我们不使用关键字'delete'来删除指针。但是,当我们以下列方式执行时,为什么有泄漏的可能性?

void k()
{
vector<m*>p;
:
:
:
} 

据我所知,删除指针是由编译器自动完成的,所以我们真的有必要删除指针吗?

8 个答案:

答案 0 :(得分:3)

  

据我所知,删除指针是由编译器自动完成的

不,不是。以下是泄漏:

vector<m*>p;
p.push_back(new m);

您需要自己删除内存:

delete p[0]; //in this case

干净的选择是使用智能指针:

vector<std::shared_ptr<m> > p;

答案 1 :(得分:3)

这取决于您放入p的内容。如果你只存储指向其他地方管理的东西(或者没有动态分配的东西)的指针,那么就没有泄漏:vector的内容将被析构函数清理。

但是,如果您执行p.push_back(new m);之类的操作,并且在delete退出之前永远不会在p的元素上调用k,那么您确实会泄漏内存。 vector(指针)的内容将被析构函数清理掉;指针指向的内存不会。

答案 2 :(得分:2)

假设您分配了向量的内容m* s)new 需要如果您想避免泄漏,请在退出该功能之前自己执行delete 。仅当内容是对象时,自动删除矢量内容才能很好地工作,而不是指向动态分配对象的指针。

您可以做的是将m*替换为std::unique_ptr<m>。现在,智能指针自动执行delete ,您无需执行任何操作。

vector<std::unique_ptr<m>>p;

或者,这也是安全的。由于您按值存储,因此当离开函数时,向量析构函数将自动销毁内容。

vector<m>p;

答案 3 :(得分:2)

只是为了解决您的初始问题:存在两种相关但不同的内存管理错误概念。我喜欢Valgrind使用的术语,这是一个流行的内存调试器:

  • 仍然可以访问的内存:这不是严格意义上的泄漏,而只是程序员的一部分懒惰。这是不洁净的,但不一定是个问题。当您只是不打算清理可以清理的东西时会发生这种情况:

    int main()
    {
        int * p = new int[100];
    }
    
    // memory at p is still reachable
    

    在这样的代码中,“仍然可以访问”的分配通常在程序结束之前使用,并且唯一合理的清理点将在最后。

  • 绝对丢失内存:这是你真正的泄漏。当您丢失对动态分配的内存的所有引用时,会发生这种情况这意味着即使在原则上你也无法释放这些资源。这是一个严重的编程错误。如果你在一个循环中泄漏内存,或者在一个被称为任意次数的东西中泄漏,你的程序很可能只是在它运行了太长时间后才会死掉,可能不会在其余的操作系统暂时无法使用之前。典型代码如下所示:

    int foo()
    {
        int * p = new int[100]();
        return p[20] + 2;
    }   // leak: We lost track of the memory at p
    
    int main()
    {
        for (std::string line; std::getline(std::cin, line); )
        {
            int * q = new int[line.length() + 1];
            q[0] = foo();  // leak 1
        }                  // leak 2: lost track of the memory at q
    }
    

上述所有情况都违反了记忆管理的基本规则,该规则首先在13世纪制定:

  

CPU,让我成为你代码的工具   如果有malloc,请写下free   哪里有newdelete
  哪里有new[]delete[]
  输入

作为推论,我们可以推断出 C ++内存管理的黄金法则,它可以大大降低内存管理漏洞的风险:

  

请勿使用new,切勿使用delete。不要使用原始指针。

关键是原始指针不带有关于可能的指针的任何所有权信息。因此,仅基于原始指针来决定是否以及如何进行任何清理是不可能的。这也是你的代码的问题 - 答案很简单,“它取决于”!

答案 4 :(得分:0)

矢量本身很好。它会自动正确地管理自己的内存。

因此答案取决于你在该载体中放置的内容。如果将指针放在堆分配的对象上,则在完成这些对象时,您有责任释放这些对象。向量不会为你做那个。

如果你没有这样做,你就会有内存泄漏。

答案 5 :(得分:0)

当您从该向量中移除元素时(使用resizeeraseclear),并假设m*已分配new,它将会不要使用delete运算符。因此,您将有内存泄漏。但是,如果这些指针指向堆栈上的变量,则不会发生内存泄漏。

编辑: 您可以在从向量中删除元素之前删除元素,但是如果您调用调整大小或清除,则很可能不会删除所有元素(除非您在清除之前循环和删除)。

答案 6 :(得分:0)

删除向量时,不会删除向量中的指针。你可以使用

vector<shared_ptr<m>> p

如果您与程序的其他部分共享指针。

答案 7 :(得分:0)

表面上的答案是否定的:你没有分配任何记忆 你的片段,所以没有泄漏。 一个更有用的答案是:它取决于角色的作用 vector是,以及你投入的内容。

对于初学者,如果类型m具有值语义,则为 可复制,您应该使用vector<m>,而不是vector<m*>。 当然,vector<m>没有泄漏的可能 (假设您已正确实施m)。

使用指针向量的最常见原因,at 至少在我工作的应用领域中,是为了 实体对象之间的导航。每个实体对象都管理 它自己的一生,或(不太常见),属于其他一些 实体对象将管理其生命周期。所以没有 泄漏的风险存在非常大的风险 一个悬空指针:指向一个物体的生命周期 结束,你必须确保从中删除任何指向它的指针 矢量。 (这通常是通过使用的一些变体来完成的 观察者模式。)

使用指针向量的另一个原因是 包含的对象是多态的,或者是大而且昂贵的 复制。在这种情况下, if 包含的对象不包含 指针,或者你可以证明周期是 不可能,指向的对象没有重要意义 内部行为(因此this)的使用非常有限, 你可以制作一个std::shared_ptr<m>的集合;在 实践中,Boost的指针容器可能更好 解决方案(并避免std::shared_ptr的风险)。这俩 shared_ptr解决方案和Boost的指针容器需要 将动态分配向量中的所有元素。