0

I just know the formal meaning of memory leaking where if we do not use the keyword 'delete' for deleting pointers. But when we perform in the following way why is there a chance of leak?

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

as far as i know the deletion of the pointers is done automatically by the compiler itself, so is it really necessary that we delete pointers at the end?

4

8 回答 8

3

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

不,这不对。以下是泄漏:

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

您需要自己删除内存:

delete p[0]; //in this case

干净的替代方法是使用智能指针:

vector<std::shared_ptr<m> > p;
于 2012-12-13T09:10:27.423 回答
3

这取决于你投入了什么p。如果您只是存储指向其他地方管理的对象(或未动态分配的对象)的指针,则不会发生泄漏: 的内容vector将被其析构函数清除。

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

于 2012-12-13T09:13:19.270 回答
2

假设您与您一起分配向量(m*s)new内容,如果您想避免泄漏,您需要在退出函数之前自己执行delete只有当内容是一个对象而不是指向动态分配的对象的指针时,向量内容的自动删除才能很好地工作。

你能做的就是m*std::unique_ptr<m>. 现在智能指针自动执行delete,您无需执行任何操作。

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

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

vector<m>p;
于 2012-12-13T09:10:09.537 回答
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. 不要使用原始指针。

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

于 2012-12-13T09:29:30.490 回答
0

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

因此,答案取决于您在该向量中放入的内容。如果您将指针指向堆分配的对象,则您有责任在使用完这些对象后释放它们。矢量不会为您做到这一点。

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

于 2012-12-13T09:11:05.320 回答
0

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

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

于 2012-12-13T09:11:41.487 回答
0

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

vector<shared_ptr<m>> p

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

于 2012-12-13T09:15:42.810 回答
0

一个肤浅的答案是否定的:你没有在你的代码片段中分配任何内存,所以不会有泄漏。一个更有用的答案是:这取决于它的作用vector是什么,以及你在其中投入了什么。

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

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

使用指针向量的另一个原因是包含的对象是多态的,或者复制起来很大且成本很高。在这种情况下,如果包含的对象不包含指针,或者您可以证明循环是不可能的,并且指向的对象没有重要的内部行为(因此只有非常有限的使用this),您可以制作一个集合std::shared_ptr<m>;在实践中,Boost 的指针容器可能是一个更好的解决方案(并且避免了 的风险std::shared_ptr)。解决方案和 Boost 的指针容器都 shared_ptr要求动态分配向量中的所有元素。

于 2012-12-13T11:38:19.443 回答