C ++编译器优化器是否允许破坏我的析构函数被多次调用?(Is the C++ compiler optimizer allowed to break my destructor ability to

编程入门 行业动态 更新时间:2024-10-14 06:18:59
C ++编译器优化器是否允许破坏我的析构函数被多次调用?(Is the C++ compiler optimizer allowed to break my destructor ability to be called multiple times?)

我们曾经接受过一位非常有经验的C ++开发人员的采访,他无法回答以下问题: 是否有必要从C ++中的派生类析构函数调用基类析构函数?

显然答案是否定的,C ++无论如何都会自动调用基类析构函数 。 但是如果我们试图打电话呢? 正如我所看到的,结果将取决于是否可以调用基类析构函数两次而不调用错误的行为。

例如在这种情况下:

class BaseSafe { public: ~BaseSafe() { } private: int data; }; class DerivedSafe { public: ~DerivedSafe() { BaseSafe::~BaseSafe(); } };

一切都会好起来的 - BaseSafe析构函数可以被安全地调用两次,程序将运行得很好。

但在这种情况下:

class BaseUnsafe { public: BaseUnsafe() { buffer = new char[100]; } ~BaseUnsafe () { delete[] buffer; } private: char* buffer; }; class DerivedUnsafe { public: ~DerivedUnsafe () { BaseUnsafe::~BaseUnsafe(); } };

明确的调用将正常运行,但对析构函数的隐式(automagic)调用将触发双重删除和未定义的行为。

看起来在第二种情况下很容易避免UB。 只需在delete[]后将buffer设置为空指针delete[] 。

但这会有帮助吗? 我的意思是析构函数只能在一个完全构造的对象上运行一次,所以优化器可以决定将设置buffer设置为空指针是没有意义的,并消除将该程序暴露给双重删除的代码。

编译器是否允许这样做?

We once had an interview with a very experienced C++ developer who couldn't answer the following question: is it necessary to call the base class destructor from the derived class destructor in C++?

Obviously the answer is no, C++ will call the base class destructor automagically anyway. But what if we attempt to do the call? As I see it the result will depend on whether the base class destructor can be called twice without invoking erroneous behavior.

For example in this case:

class BaseSafe { public: ~BaseSafe() { } private: int data; }; class DerivedSafe { public: ~DerivedSafe() { BaseSafe::~BaseSafe(); } };

everything will be fine - the BaseSafe destructor can be called twice safely and the program will run allright.

But in this case:

class BaseUnsafe { public: BaseUnsafe() { buffer = new char[100]; } ~BaseUnsafe () { delete[] buffer; } private: char* buffer; }; class DerivedUnsafe { public: ~DerivedUnsafe () { BaseUnsafe::~BaseUnsafe(); } };

the explicic call will run fine, but then the implicit (automagic) call to the destructor will trigger double-delete and undefined behavior.

Looks like it is easy to avoid the UB in the second case. Just set buffer to null pointer after delete[].

But will this help? I mean the destructor is expected to only be run once on a fully constructed object, so the optimizer could decide that setting buffer to null pointer makes no sense and eliminate that code exposing the program to double-delete.

Is the compiler allowed to do that?

最满意答案

标准12.4 / 14

一旦为对象调用析构函数,该对象就不再存在; 如果析构函数针对其生存期已结束的对象(3.8)进行调用,则行为未定义。

所以我猜想编译器应该可以自由地将缓冲区的设置优化为null,因为在调用析构函数之后对象不再存在。

但是,即使缓冲区的设置为null并未被编译器清除,看起来像调用析构函数两次会导致UB。

Standard 12.4/14

Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended (3.8).

So I guess the compiler should be free to optimize away the setting of buffer to null since the object no longer exists after calling the destructor.

But even if the setting of the buffer to null wasn't removed by the compiler, it seems like calling the destructor twice would result in UB.

更多推荐

本文发布于:2023-08-06 09:08:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1446899.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:编译器   函数   optimizer   allowed   break

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!