【问题标题】:the exact operation of the delete operator删除操作符的确切操作
【发布时间】:2016-02-20 16:33:08
【问题描述】:

我听说过很多关于 C++ delete operator 并且到目前为止也使用过很多,但我不知道它的真正工作是什么.
我在网上看到的是关于“Deallocating storage space”的讨论,但对我来说完全理解这个问题并没有什么意义。

请看下面代码的sn-p。

int main()
{
   int* p = new int(6);
   cout << *p << endl;
   delete p;
}

指针p 有自己的地址,因为它是一个变量(#1)。指针p 本身也有一个地址,因为它是一个指针(#2)。该对象(未命名)在其内存块中包含值 6,并且该内存块的地址与#2 的地址相同。 (因为指针使用该地址指向该对象。)

现在,地址#1 和#2 在执行delete; 后会发生什么?
C++ 语言对此有何看法?
以及各种编译器对案例的影响是什么?

【问题讨论】:

  • 这是一个delete 表达式,而不是delete 运算符的调用。后者是一个释放函数,通常由delete 表达式调用。在delete 表达式之后调用一个对象析构函数(或者对于一个数组,一个这样的序列)。

标签: c++ pointers delete-operator


【解决方案1】:

现在,地址#1、#2在执行删除后会发生什么; (在代码中)好吗?

指针p 将有一个未定义的值,但它会保留其地址(“#1”)。

*p(地址为“#2”)的int 对象不再存在。该地址现在描述了可供将来分配使用的内存。


C++ 语言对此有何看法?

这个:

[C++14: 5.3.5/1]:delete-expression 运算符会破坏由 new-expression 创建的最派生对象 (1.8) 或数组。 [..]

[C++14: 5.3.5/7]:如果delete-expression的操作数的值不是空指针值,那么:

  • 如果对要删除的对象的新表达式的分配调用未被省略 (5.3.4),则删除表达式应调用解除分配函数 (3.7.4.2)。从 new-expression 的分配调用返回的值应作为第一个参数传递给释放函数。
  • 否则,删除表达式将不会调用释放函数 (3.7.4.2)。

各种编译器对案例的影响是什么?

只要它们合规,就没有。所有编译器的行为方式必须相同。

【讨论】:

  • 您确定“指针 p 不会受到影响”吗?从我读过的其他SO答案中,例如stackoverflow.com/questions/704466/…stackoverflow.com/questions/5002055/…
  • @4386427:对的好点;我的意思是它的存在不会受到影响,也不会移动到任何地方,但因为它的价值可能是任何具有误导性的东西。
  • @PreferenceBean:非常感谢您的版本和回答。我明白了这个主题。 (尤其是你的答案部分)。但我不明白[C++14: 5.3.5/1] 中的“最衍生对象”是什么意思。 [C++14: 5.3.5/7] 部分对我来说有点复杂:-)
  • @franky:是的,标准语言需要一些时间来适应它。出于本次对话的目的,您可以将其读为“对象”。这段话是在对冲它的赌注,因为当继承和多态性进入其中时,事情会变得有点复杂。
【解决方案2】:
int main() {
    int* p;             // p is at address #1 and the value uninitialized. p will
                        // be at address #1 throughout the whole program.
                        // It is only the value of p that can change.

    p = new int(6);     // The value of p is set to address #2 and your
                        // program now has ownership of sizeof(int) bytes
                        // starting from address #2. The int at address #2
                        // is initialized with the value 6.
    cout << *p << endl;

    delete p;           // Your program releases ownership of the memory at
                        // address #2 and you are not allowed to use it anymore.
                        // The value of p is undefined.

    return 0;
}

【讨论】:

【解决方案3】:

delete p 之后,p 仍然具有与以前相同的地址。对象已经消失,所以它没有地址。它曾经占用的字节可能用于其他用途或可能已返回给操作系统;如果不调用未定义的行为,就无法查看它们。

p 的值不再有用 - 你不能对 p 做很多事情,除非给它分配一个新值或者让它被销毁。

这就是语言所说的,编译器会实现它。

这里有更多详细信息:http://en.cppreference.com/w/cpp/language/delete

【讨论】:

  • 感谢您的回答。我认为在(我的代码片段)中我们没有任何泄漏,但我们有一个悬空指针(删除后的p)。你同意?如果是这样,如何避免它被吊起来?比如如何销毁?
  • @franky:如果您绝对需要手动进行动态分配,请使用诸如std::unique_ptrstd::shared_ptr 之类的智能指针来处理生命周期管理。不要将原始指针用作所有者,仅将它们用作简单的引用者。不要采用将原始指针归零的错误做法:它会给人一种错误的安全感,并且会阻碍工具检测事物的努力。
  • 谢谢,我只是想熟悉一下。
  • @franky 通过从函数返回,您可以安全而简洁地销毁p
【解决方案4】:

关于

删除操作符的具体操作

问题中的示例代码:

delete p;

这是一个delete 表达式,而不是直接调用delete 运算符。运算符是一个释放函数,通常由delete 表达式调用,在delete 表达式调用对象析构函数(或数组,这样的序列)之后。以下是发生的事情:

  1. 如果 p 指向类类型的对象,则调用其析构函数来清理事物,例如释放资源。

  2. 调用相关的释放函数operator delete 来释放内存。这通常是全局operator delete,但也可以是相关类定义的operator delete

值得注意的是,对于放置 new 表达式,如果在评估该 new 表达式期间构造失败,则使用相同的分配器参数调用放置释放函数,但稍后的 delete 表达式仅调用普通标准论据operator delete。我不知道这样做的理由。但它导致了一些错误,尤其是 MFC 中一个臭名昭著的错误,它仅在调试版本中出现,内存泄漏。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 2016-03-01
    • 2015-04-10
    相关资源
    最近更新 更多