24

我偶然发现了以下代码片段:

#include <iostream>
#include <string>
using namespace std;
class First
{
    string *s;
    public:
    First() { s = new string("Text");}
    ~First() { delete s;}
    void Print(){ cout<<*s;}
};

int main()
{
    First FirstObject;
    FirstObject.Print();
    FirstObject.~First();
}

文本说这个片段应该会导致运行时错误。现在,我不太确定,所以我尝试编译并运行它。有效。奇怪的是,尽管所涉及的数据很简单,但程序在打印“文本”后结结巴巴,一秒钟后就完成了。

我添加了一个要打印到析构函数的字符串,因为我不确定显式调用这样的析构函数是否合法。该程序打印了两次字符串。所以我的猜测是析构函数被调用了两次,因为正常的程序终止不知道显式调用并试图再次销毁对象。

一个简单的搜索确认在自动化对象上显式调用析构函数是危险的,因为第二次调用(当对象超出范围时)具有未定义的行为。所以我很幸运我的编译器(VS 2017)或这个特定的程序。

关于运行时错误的文本是否完全错误?或者运行时错误真的很常见吗?或者也许我的编译器针对这种事情实施了某种防护机制?

4

3 回答 3

35

一个简单的搜索确认在自动化对象上显式调用析构函数是危险的,因为第二次调用(当对象超出范围时)具有未定义的行为。

那是真实的。如果您使用自动存储显式销毁对象,则会调用未定义的行为。了解更多

所以我很幸运我的编译器(VS 2017)或这个特定的程序。

我会说你倒霉。UB 可能发生的最好的(对你来说,编码器)是在第一次运行时崩溃。如果它看起来工作正常,那么崩溃可能会在 2038 年 1 月 19 日在生产中发生。

关于运行时错误的文本是否完全错误?或者运行时错误真的很常见吗?或者也许我的编译器针对这种事情实施了某种防护机制?

是的,文字有点错误。未定义的行为是未定义的。运行时错误只是众多可能性之一(包括鼻恶魔)。

关于未定义行为的好读物:什么是未定义行为?

于 2018-11-12T12:48:29.857 回答
15

不,这只是 C++ 标准草案[class.dtor]p16中未定义的行为:

一旦为对象调用析构函数,该对象就不再存在;如果为生命周期已结束的对象([basic.life])调用析构函数,则行为未定义。[ 示例:如果自动对象的析构函数被显式调用,并且块随后以通常会调用对象的隐式销毁的方式离开,则行为未定义。—结束示例</p>

我们可以从未定义行为的定义中看出:

本文件没有要求的行为

你不能对结果抱有任何期望。对于作者来说,在特定机器上使用特定选项的特定编译器可能会以这种方式表现,但我们不能指望它是可移植的或可靠的结果。尽管在某些情况下,实现确实会尝试获得特定结果,但这只是另一种可接受的未定义行为形式。

此外, [class.dtor]p15为我在上面引用的规范部分提供了更多背景信息:

[注意:很少需要显式调用析构函数。这种调用的一种用途是使用放置新表达式放置在特定地址的对象。为了处理专用硬件资源和编写内存管理工具,可能需要使用对象的显式放置和销毁。例如,

void* operator new(std::size_t, void* p) { return p; }
struct X {
  X(int);
  ~X();
};
void f(X* p);

void g() {                      // rare, specialized use:
  char* buf = new char[sizeof(X)];
  X* p = new(buf) X(222);       // use buf[] and initialize
  f(p);
  p->X::~X();                   // cleanup
}

——尾注]

于 2018-11-12T14:15:24.577 回答
9

关于运行时错误的文本是否完全错误?

这是错误的。

或者运行时错误真的很常见吗?或者也许我的编译器针对这种事情实施了某种防护机制?

您无法知道,这就是您的代码调用Undefined Behavior时发生的情况;你不知道执行它时会发生什么。

在您的情况下,您(不)幸运*并且它起作用了,而对我而言,它导致了错误(双重免费)。


*因为如果您收到错误,您将开始调试,否则,例如在大型项目中,您可能会错过它......

于 2018-11-12T12:51:26.480 回答