自动对象的覆盖析构函数是否定义良好? [英] Is overriding destructor for automatic object well defined?

查看:33
本文介绍了自动对象的覆盖析构函数是否定义良好?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一种情况,我想从调用函数中导入一个又一个调用.为此,我决定覆盖一个虚拟析构函数:

I had a situation where I wanted to import a call after another call from the calling function. I decided to override a virtual destructor for the purpose:

#include <iostream>

struct type {
    virtual ~type() {
        std::cout << "ordinary" << std::endl;
    }
    void method() {
        struct method_called : type {
            virtual ~method_called() override {
                std::cout << "method called" << std::endl;
            }
        };

        this->~type();

        new (this) method_called{};
    }
};

int main() {
    
    std::cout << "ordinary expected" << std::endl;

    {
        type obj;
    }

    std::cout << "method expected" << std::endl;

    {
        type obj;

        obj.method();
    }

    std::cout << "method expected" << std::endl;

    type* pobj = new type{};

    pobj->method();

    delete pobj;
}

似乎只能使用动态分配调用覆盖的析构函数.这是故意的吗?

It seems the overridden destructor is called only using dynamic allocation. Is this intended?

海湾合作委员会 Godbolt.

推荐答案

this->~type();

一旦你这样做,任何指向对象的指针或引用该行之前存在的对象的变量的任何取消引用都是未定义的行为.

Any dereference of any pointer pointing to the object or variable referring to the object that exists prior to this line is undefined behavior once you do this.

这包括自动存储析构函数.

This includes the automatic storage destructor.

为了避免在执行此操作后 main 中出现未定义的行为,您必须调用 exit 或类似地永远不要从变量所在的作用域返回.

To avoid undefined behaviour in main after doing this, you'd have to call exit or similarly never return from the scope where the variable exists.

当析构函数完成时,对象的生命周期就结束了.之后几乎任何使用该对象都会触发 UB.您可以重复使用存储:

By the time the destructor is finished, the objects lifetime is over. Almost any use of the object after that triggers UB. You can reuse the storage:

    new (this) method_called{};

这会在 this 引用的存储中创建一个不同的对象.如果这个存储有足够的对齐和大小,那么这样做是没问题的.正确处理非常棘手,因为安全获取指向这个新创建对象的指针的少数方法之一是将返回值记录到新位置,如下所示:

This creates an distinct object in the storage that this refers to. If this storage has sufficient alignment and size, doing so is fine. It is extremely tricky to get right, because one of the few ways to safely get a pointer to this newly created object is by recording the return value to placement new like this:

auto* pmc = new (this) method_called{};

你不这样做.

{
    type obj;

    obj.method();
}

这是未定义的行为.如果此代码在或将在您的程序执行过程中的任何时候执行,则该标准不限制您的编译器生成的程序执行的操作.

this is undefined behavior. The standard does not restrict what the program produced by your compiler does if this code is or would be executed at any point in your programs execution.

type* pobj = new type{};

pobj->method();

delete pobj;

原来是这样.

这篇关于自动对象的覆盖析构函数是否定义良好?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆