代码之家  ›  专栏  ›  技术社区  ›  Chiel

销毁顺序父级和子级

  •  5
  • Chiel  · 技术社区  · 6 年前

    为什么C++会破坏 Parent Child 班当对象超出范围时,首先销毁 shared_ptr 然后自毁?在我的工作流中,这会导致问题,因为我的 父母亲 类正在管理 小孩 类使用。

    #include <iostream>
    #include <memory>
    
    class Child;
    
    class Parent
    {
        public:
            Parent() :
                child(std::make_shared<Child>())
            { 
                std::cout << "Constructing parent" << std::endl;
            }
            ~Parent() { std::cout << "Destructing parent" << std::endl; }
        private:
            std::shared_ptr<Child> child;
    };
    
    class Child
    {
        public:
            Child()
            { 
                std::cout << "Constructing child" << std::endl;
            }
            ~Child() { std::cout << "Destructing child" << std::endl; }
    };
    
    int main()
    {
        Parent parent;
        return 0;
    }
    

    编辑
    根据这些评论,我觉得我的问题需要更多的解释。我的孩子都在 std::shared_ptr ,当父级超出范围时将释放。我的主程序是CUDA程序,家长可以访问GPU设备。如果父级被删除,我将无法再访问GPU。然而,子级的析构函数需要释放其GPU内存,因此,我希望在父级超出作用域之前执行此操作。但这意味着我必须手动删除智能指针,在我看来,这有点违背了它们的目的。

    2 回复  |  直到 6 年前
        1
  •  5
  •   Rotem    6 年前

    这个 destruction order 定义为(重点矿山):

    对于用户定义或隐式定义的析构函数, 在执行析构函数体之后,编译器为类的所有非静态非变量成员调用析构函数 ,以声明的相反顺序,然后它以构造的相反顺序调用所有直接非虚拟基类的析构函数(这反过来又调用其成员的析构函数及其基类等),然后,如果此对象是派生类最多的对象,则它调用所有虚拟基类的析构函数。

    一个很好的理由是 Parent 可能需要访问其成员以释放资源,但并非每个对象都是自包含的。

        2
  •  2
  •   amc176    6 年前

    当对象超出范围时,首先销毁共享的PTR,然后再销毁自身,这难道不是更有逻辑吗?

    不完全是 Parent 可能需要访问某些成员以进行某种清理,因此它们需要在构造函数体中可以访问并处于活动状态。如果你需要销毁 Child 首先,您可以始终手动执行:

    ~Parent() { 
      child.reset();
      // do the rest ...
    }