C++ 在构造函数中删除后继续执行

C++ 在构造函数中删除后继续执行,c++,C++,我在检查一些代码时遇到了以下情况。它工作得很好,但对我来说,这听起来像是一种未定义的行为,但我不知道搜索什么以及如何证明它 #include <memory> #include <functional> #include <string> #include <iostream> class Child { public: Child() { std::cout << "Child created\n";

我在检查一些代码时遇到了以下情况。它工作得很好,但对我来说,这听起来像是一种未定义的行为,但我不知道搜索什么以及如何证明它

#include <memory>
#include <functional>
#include <string>
#include <iostream>

class Child
{
public:
    Child()
    {
        std::cout << "Child created\n";
    }
    ~Child()
    {
        std::cout << "Child is dead\n";
    }
};

class Parent
{
    std::unique_ptr<Child> m_child;
public:
    using Callback = std::function<void()>;
    Parent(const Callback& killMe)
    {
        std::cout << "Parent created\n";
        killMe();
        m_child = std::make_unique<Child>();
    }

    ~Parent()
    {
        std::cout << "Parent is dead\n";
    }
};

class GrandParent
{
    std::unique_ptr<Parent> m_child;
public:
    GrandParent()
    {
        m_child = std::make_unique<Parent>([this]() { KillChild(); });
    }

    void KillChild()
    {
        m_child.reset();
    }
};

int main()
{
    {
        GrandParent gp;
    }
    return 0;
}

代码没有UB只是因为它没有按预期工作

    m_child = std::make_unique<Parent>([this]() { KillChild(); })

代码没有UB只是因为它没有按预期工作

    m_child = std::make_unique<Parent>([this]() { KillChild(); })

…对于用户定义或隐式定义的析构函数,在执行析构函数体后,编译器为类的所有非静态非变量成员调用析构函数,。。。请参见此处的销毁顺序:因此,在执行Parent::~Parent之后,将销毁Parent的成员。如果killMe做了什么,那么不考虑它的定义是一个错误。@PierrePodevin由祖父母传递给父代的回调函数。@RichardCriten祖父母有一个指向父代的指针。构造父对象时,它将回调传递给祖父母::KillChild,这将调用当前正在构造的父对象上的deletein reset。删除这个问题有很好的理由说明为什么UB在删除后会访问成员,但我想知道从构造函数中调用析构函数是否是实际定义的行为。您试图实现什么?它之所以有效,是因为在尚未分配m_child时调用了m_child.reset,因此成为一个no-op。否则killMe将删除该实例和后续的m_child=。。。将访问已删除的对象…对于用户定义或隐式定义的析构函数,在执行析构函数体后,编译器将为类的所有非静态非变量成员调用析构函数,。。。请参见此处的销毁顺序:因此,在执行Parent::~Parent之后,将销毁Parent的成员。如果killMe做了什么,那么不考虑它的定义是一个错误。@PierrePodevin由祖父母传递给父代的回调函数。@RichardCriten祖父母有一个指向父代的指针。构造父对象时,它将回调传递给祖父母::KillChild,这将调用当前正在构造的父对象上的deletein reset。删除这个问题有很好的理由说明为什么UB在删除后会访问成员,但我想知道从构造函数中调用析构函数是否是实际定义的行为。您试图实现什么?它之所以有效,是因为在尚未分配m_child时调用了m_child.reset,因此成为一个no-op。否则killMe将删除该实例和后续的m_child=。。。将访问已删除的对象。
killMe();
m_child = std::make_unique<Child>(); // is actually this->m_child = , but *this* is gone now