【问题标题】:Memory leak prevention C++ (Am I right or wrong?)内存泄漏预防 C++(我是对还是错?)
【发布时间】:2014-12-25 23:51:30
【问题描述】:

我已经在互联网上搜索了几个小时,并想出了这些步骤来防止内存泄漏(不使用智能指针和高级工具等)。如果以下发现有任何问题,请告诉我...提前致谢。

  1. 每一个新的都应该有一个删除。
  2. 如果 new 在类中,则将 delete 放入析构函数中会处理动态分配的内存。
  3. 如果您在 main 中从类 foo 中创建一个新对象 obj,那么您将不得不显式删除 obj。
  4. 如果您有多维动态数组,则必须删除这两个级别。 (我有点不确定这是否安全......我认为只有一次删除 ptr 可能会做到这一点,但经过仔细考虑后,我认为它是一个动态数组的动态数组,应该将每个动态数组分别视为一个动态数组)。

前 1 个。

char *ptr;
ptr = new char[size];
// Some Code here
delete ptr;

前 2.

//foo.h
class foo { 
private:
    char * ptr;
public
    foo();
    ~foo();
};
// foo.cpp
foo::foo()
{
    ptr = new char[100];
    for (int i = 0; i < 100; i++)
        ptr[i] = i;
}

foo::~foo()
{
    delete ptr;
}

前 3.

//main.cpp   foo class stays the same as ex 2.
int main()
{
    foo obj = new foo();
    // Some code here
    delete obj;
    return 0;
}

前 4.

//foo.h
class foo {
private:
    char ** ptr;
public
    foo();
    ~foo();
};

//foo.cpp
foo::foo()
{
    ptr = new char[100];
    for (int i = 0; i < 100; i++)
        ptr[i] = new char[100];
    for (int i = 0; i < 100; i++)
        for (int j = 0; j < 100; j++)
            ptr[i][j] = i;
}

foo::~foo()
{
    for (int i = 0; i < 100; i++)
        delete ptr[i];
    delete ptr;
}

【问题讨论】:

  • 在 ex1 中,您必须调用 delete[] ptr,因为它是 char 的数组,请看这里:cplusplus.com/reference/new/operator%20delete%5B%5D ex2 上的相同问题,在析构函数中添加 []。 Ex3 没问题。对于 Ex4,在析构函数中为 delete 添加相同的 []。希望对您有所帮助!
  • 这个问题似乎离题了,这里没有真正的问题,你只是想让我们回顾你的例子。因此,您应该将其发布到 codereview.stackexchange.com
  • 5. 如果您在new 时使用[],则必须delete 时使用[]`。 例如。 5 o = new Object; delete o;array = new char[100];删除[] 数组;`.
  • 智能指针和向量等比手动管理内存要少得多。我不会称其为高级。向量在大多数情况下可以像数组一样使用,智能指针在大多数情况下可以像指针一样使用。
  • 你的策略中有一个明显的遗漏:深拷贝。例如,在你的前 2 和 4 中,你需要实现深拷贝(并且也移动),否则,你的对象的意外拷贝会导致内存的双重删除(这通常会导致堆损坏,这真的很糟糕!)。见the Big Five

标签: c++ pointers memory-leaks dynamic-memory-allocation


【解决方案1】:

以下是您在自行管理内存时需要注意的一些提示:-

首先也是最重要的是:-

1) 始终将 delete 与 new 和 delete[] 与 new[] 一起使用。混合使用会导致未定义的行为。

2) 永远不要组合 malloc/delete 或 new/free。

对于您的问题“如果您有多维动态数组,则必须删除两个级别。” 是的,你必须照顾他们。

您提到的事情是正确的,即每当您在堆中分配内存时,您都必须明确删除内存。尽管您错过了围绕 RAII 的一个重要方面。假设有一个函数负责分配/解除分配。

void fun ()
{
 1) int* ptr;
 2) ptr = new int;   //allocated memory.

 3) ...              //do something with ptr.

 4) delete ptr;     //done with ptr now delete it.
}

现在您可以删除使用 new 分配的内存了。但是,程序执行甚至可能无法到达您的删除。 (以防在 STEP#3 中引发异常)。这种情况会构成内存泄漏。

为了解决这些问题,我们有基于 RAII 概念的智能指针。只要超出范围,它们就会自动删除它们所引用的内存,这意味着您不需要处理内存管理。

【讨论】:

  • 不要误以为智能指针可以解决所有问题。 :) 你确实有一点需要照顾;这只是更多的设计工作和更少的 bean 计数。 (例如,您需要选择正确类型的智能指针。并且您必须正确使用它们。)
  • 我认为您的意思是说 RAII,而不是 RTTI。这与RTTI(运行时类型识别)无关,但与RAII(资源获取即初始化)有关。
【解决方案2】:
  1. 每一个新的都应该有一个删除。

是的。更准确地说:每个new 必须有一个匹配的delete,每个new[] 必须有一个匹配的delete[]

  1. 如果 new 在类中,则将 delete 放入析构函数中会处理动态分配的内存。

不!您还应该注意通过复制构造函数或赋值对副本会发生什么,除非您明确禁止这些操作。详情请见What is The Rule of Three?

  1. 如果您在 main 中从类 foo 中创建一个新对象 obj,那么您将不得不显式删除 obj。

??见 1.?

  1. 如果您有多维动态数组,则必须删除两个级别。 (我有点不确定这是否安全......我认为只有一次删除 ptr 可能会做到这一点,但经过仔细考虑后,我认为它是一个动态数组的动态数组,应该将每个动态数组分别视为一个动态数组)。

是的,如果您使用原始指针,无论有多少间接级别,您都必须始终注意正确的内存管理。


我最后的建议是,不要理会这些问题,而是使用&lt;memory&gt; 智能指针和standard c++ containers 提供的东西。

不要直接使用new/delete,除非您 100% 确定自己在做什么,并且 200% 确定自己确实需要这样做。


当您询问实际问题时:

(例如 2。)deletenew char[] 不匹配

ptr = new char[100];
           // ^^^^^

foo::~foo() {
    delete [] ptr;
        // ^^ put the square brackets there
}

同样适用于(例如 4.)

【讨论】:

  • 很好的建议。非常感谢你的帮助。我想我忘了提到我正在学习 C++,并且这个类项目需要使用它们。
  • @AliZand:一位好老师应该先向您展示普通方法(向量、字符串、智能指针等),然后再深入研究手册内容(这非常罕见,以至于许多程序员从不需要它)
猜你喜欢
  • 1970-01-01
  • 2012-07-12
  • 2011-10-29
  • 1970-01-01
  • 2011-11-15
  • 2012-06-24
  • 2018-05-31
  • 2015-02-05
相关资源
最近更新 更多