【问题标题】:C++: Default Destructor: Does it Delete Arrays Pointed to By Member Pointer?C++:默认析构函数:它会删除成员指针指向的数组吗?
【发布时间】:2020-07-24 14:27:08
【问题描述】:

如果我这样声明类 MyObj:

class MyObj: {
  private:
    uint8_t *arrayPtr;
  public:
    void makeArray();
}

void MyObj::makeArray() {
  arrayPtr = new uint8_t [10];
}

然后我打电话:

void func() {
  MyObj testObj;
  testObj.makeArray();
}

既然 func 已经运行并完成并且 testObj 可以被忘记,那么 10 字节数组是否会从堆栈中删除?还是我需要为 MyObj 创建一个显式析构函数来测试数组是否存在并在其上调用 delete 函数?

【问题讨论】:

  • 是的,你需要做些delete 的事情。经验法则,没有例外,100% 保证:如果你 new 某事,它必须在某个时间点被删除一次。结束。
  • 针对@cigien 进行了编辑以确保清晰。
  • 实现这一点相当困难且容易出错。编译器需要确保它指向动态分配的内存,知道是使用delete 还是delete[],并且知道该对象是该内存块的唯一(强)所有者。这些领域的任何不确定性都会导致不正确的删除,可以说比默认情况下的内存泄漏更有害。它也将无法处理任何非内存资源。

标签: c++ pointers memory-management memory-leaks


【解决方案1】:

这段代码sn-p中不能调用delete

MyObj testObj;
testObj.makeArray();
delete testObj;

因为 testObj 不是由使用 new 运算符分配的内存地址分配的指针。

你需要在类定义中至少添加一个初始化器和析构器

class MyObj {
  private:
    uint8_t *arrayPtr = nullptr;
  public:
    ~MyObj() { delete [] arrayPtr; }
    void makeArray();
};

请注意,要么将复制构造函数和复制赋值运算符定义为已删除,要么必须显式定义它们。

还要记住函数 makeArray 是不安全的。如果用户第二次调用它会出现内存泄漏,因为之前分配的内存不会被删除。

而且你没有一个数组作为类的数据成员。你有一个指针。该指针将与包含该指针的对象一起从堆栈中释放。但是,如果不调用操作符 delete [],动态分配的数组将不会被释放。

【讨论】:

  • 那个析构函数似乎并不关心arrayPtr指向的数组中有多少元素。析构函数自己知道有多少元素吗?
  • 即使在sn-ps中也请不要破坏0/3/5的规则
  • @BoThompson 分配内存时存储此信息并返回指向已分配内存的指针。
  • @MikeVine该问题与删除运算符有关。没有必要触及另一个问题。
  • 等一下,我的问题不是特定于删除运算符;我的问题的最初编辑有一个不好的例子。我已经重新措辞它不包含明确的删除操作。您的答案在这个新案例中仍然有效吗?
【解决方案2】:

您不能在具有自动存储持续时间的对象上调用delete(“在堆栈上”)。它会导致程序的未定义行为。

您必须准确地根据从new(或new[])返回的指针值调用delete(或delete[]),这不会自动为您完成。

所以是的,您需要添加一个执行删除操作的析构函数,并且您必须小心遵循rule-of-0/3/5,这意味着您还需要编写具有正确语义的复制构造函数和赋值运算符.

您可以通过使用std::vector<uint8_t> 代替arrayPtr 来避免所有麻烦。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-29
    • 1970-01-01
    • 1970-01-01
    • 2018-09-12
    • 2010-10-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多