【问题标题】:What are the dynamics of the C++ delete statement?C++ delete 语句的动态是什么?
【发布时间】:2015-07-12 04:12:00
【问题描述】:

这只是出于好奇,因为除了最基本的用途外,我没有在 c++ 中使用过newdelete

我知道delete 会释放内存。我想知道的是它如何处理更复杂的情况?

例如,如果我有一个这样的用户定义类:

class MyClass
{
public:
    MyClass();
    ~MyClass()
    {
        delete [] intArray;
    }
    //public members here
private:
    int* intArray;
};

假设该类以某种方式为intArray 分配内存,然后在析构函数中释放它,如果我这样使用该类会怎样:MyClass* myClass = new MyClass(); 并稍后用delete myclass; 释放它

delete如何处理所有内存的释放?是否首先调用类析构函数以释放该类分配的所有内存(即int* intArray),然后释放分配给该类的内存?

如果我有这样的课程会怎样:

class MyClass
{
public:
    MyClass();
    ~MyClass()
    {
        delete anotherMyClass;
    }
    //public members here
private:
    MyClass* anotherMyClass;
};

假设 anotherMyClass 没有分配给构造函数,这会很快耗尽内存,如果有一个 MyClasses 链像链表一样相互连接怎么办?在这种情况下,析构函数中的删除语句会起作用吗?当析构函数被调用时,每个anotherMyClass 会被递归释放吗?

您所知道的newdelete 语句是否有任何特定的奇怪技巧或注意事项?

【问题讨论】:

  • 别忘了拥有自己的拷贝构造函数和赋值运算符。处理类的指针成员在其中动态分配的内存。
  • 是的,你已经搞定了。您已经回答了所有自己的问题。

标签: c++ new-operator delete-operator


【解决方案1】:

给定一个指向动态分配对象的指针 (p),delete 做了两件事:

  1. 它调用动态分配对象的析构函数。请注意,当 ~MyClass() 完成时,将调用任何类类型成员变量的析构函数。
  2. 它释放动态分配的对象占用的内存。

它不会在对象的成员变量中搜索其他指向 free 的指针;它不会释放任何其他内存,也不会做任何其他事情。

如果需要释放intArray指向的内存,需要在MyClass的析构函数中delete

但是,在几乎所有 C++ 代码中,您无需担心这一点。您应该使用像shared_ptrunique_ptrauto_ptrscoped_ptr 这样的智能指针来自动管理动态分配的对象。手动资源管理充其量是困难的,应尽可能避免。

这是更广泛的成语“范围绑定资源管理”(SBRM,也称为资源获取即初始化或 RAII)的一部分。到目前为止,这是在 C++ 代码中理解和使用的最重要的设计模式。

如果你在课堂上声明了这一点:

boost::scoped_ptr<int> intArray;

然后当scoped_ptr&lt;int&gt; 对象被销毁时,它将释放它持有的指针。然后,您不必做任何工作来手动销毁该对象。

在编写良好的现代 C++ 代码中,您应该很少需要手动使用 delete。应该使用智能指针和其他 SBRM 容器来管理需要清理的任何类型的资源,包括动态分配的对象。


在您的第二个示例中,给定一个如下所示的链表:

x -> y -> z -> 0

您将有一个如下所示的操作顺序:

delete x;
  x.~MyClass();
    delete y;
      y.~MyClass();
        delete z;
          z.~MyClass();
            delete 0;
          [free memory occupied by z]
      [free memory occupied by y]
  [free memory occupied by x]

链表中的对象会以相反的顺序被销毁。

【讨论】:

  • 虽然,析构函数的调用是有保证的,除了......异常(我猜是什么时候断电)。所有成员变量的析构函数也被调用。您可以通过 RAII 技术利用这种“级联”。
  • 换句话说,delete 不会“释放该类分配的所有内存”,但被销毁的对象本身可能会这样做并且可能应该这样做。
  • 修正了我的问题中的一些措辞。关于第一个用户类示例的问题并不完全清楚。我想知道是否先调用析构函数然后释放内存,但你们回答了这个问题。
  • 另外,如果你的类有智能指针的成员(或者有析构函数),对它们的析构函数调用被包含在你的类析构函数的隐式最后一步。如果您设法在不调用类析构函数的情况下释放内存,则也不会调用成员析构函数。
【解决方案2】:
delete intArray;

我假设intArray 指向int 数组的第一个元素?在这种情况下,delete intArray 会产生未定义的行为。如果你通过new[]分配,你必须通过delete[]释放。

delete[] intArray;

是的,我知道,delete intArray 可能appear 在某些编译器选项下具有某些编译器版本的某些系统上工作得很好——或者它可能不会。那是 undefined behavior 给你的。

另外,您应该关注Rule of Three。定义自己的析构函数但依赖隐式定义的复制构造函数和复制赋值运算符是灾难的根源。

【讨论】:

    猜你喜欢
    • 2021-09-09
    • 2015-06-15
    • 2011-05-05
    • 1970-01-01
    • 2010-12-29
    • 2010-10-21
    • 1970-01-01
    • 2019-01-26
    • 2021-08-07
    相关资源
    最近更新 更多