【问题标题】:Is overriding destructor for automatic object well defined?自动对象的重写析构函数是否定义良好?
【发布时间】:2021-11-02 00:59:37
【问题描述】:

我有一种情况,我想在调用函数的另一个调用之后导入一个调用。为此,我决定重写一个虚拟析构函数:

#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;
}

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

GCC godbolt.

【问题讨论】:

  • 在调用this-&gt;~type() 之后,this 的使用具有未定义的行为。您的代码不会以某种方式将 type 的实例变形为(本地定义的)method_type 的实例,这(似乎是)您正在尝试做的事情。
  • obj.method(); 不会更改 obj 类型。这仍然是type。编译器在}之后直接调用析构函数type::~type,而不是使用vtbl,因为它知道obj的类型。
  • @Peter 我仍然不相信 - 你能写一个答案吗?可能引用标准。或者如果有的话,可以链接另一个类似的问题。
  • @AnArrayOfFunctions 尽管有太多的语言律师暗示并非如此,但该标准并未详细说明未定义行为的每个实例。有很多情况下,行为是由于遗漏而未定义的——即标准没有对发生的事情指定任何约束。那是因为标准委员会成员只是没有预料到这种用法的凡人(如果没有人预料到尝试执行 X 的代码,则不可能指定由于此类尝试而发生的限制,同样不可能指定没有约束,即使其未定义)。

标签: c++ inheritance polymorphism virtual destructor


【解决方案1】:
this->~type();

执行此操作后,任何指向对象的指针或引用此行之前存在的对象的变量的任何取消引用都是未定义的行为。

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

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

当析构函数完成时,对象的生命周期已经结束。之后几乎所有对象的使用都会触发 UB。您可以重复使用存储空间:

    new (this) method_called{};

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

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

你不要那样做。

{
    type obj;

    obj.method();
}

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

type* pobj = new type{};

pobj->method();

delete pobj;

原来如此。

【讨论】:

    猜你喜欢
    • 2021-10-28
    • 2020-11-14
    • 1970-01-01
    • 2017-10-11
    • 1970-01-01
    • 2012-03-18
    • 2012-04-29
    • 2011-10-04
    相关资源
    最近更新 更多