📜  在C++中使用shared_ptr进行虚拟销毁

📅  最后修改于: 2021-05-30 14:30:46             🧑  作者: Mango

先决条件: shared_ptr,虚拟析构函数

众所周知,使用指向具有非虚拟析构函数的基类的指针删除派生类对象会导致未定义的行为。因此,我们使基类的析构函数成为虚拟的,以便以正确的顺序(即创建它们的相反顺序)正确删除多态对象。

也可以通过使用shared_ptr来实现类似的行为,而无需将基类的析构函数虚拟化。让我们看一下以下代码:

// Program to show the order of destruction of objects using
// shared_ptr
#include 
#include 
using namespace std;
  
class Base {
public:
    Base()
    {
        cout << "Constructing Base" << endl;
    }
    ~Base()
    {
        cout << "Destructing Base" << endl;
    }
};
  
class Derived : public Base {
public:
    Derived()
    {
        cout << "Constructing Derived" << endl;
    }
    ~Derived()
    {
        cout << "Destructing Derived" << endl;
    }
};
  
int main()
{
    std::shared_ptr sp{ new Derived };
  
    // make_shared can also be used to create sp.
    // std::shared_ptr sp{std::make_shared()};
    // Use sp
}

输出:

Constructing Base
Constructing Derived
Destructing Derived
Destructing Base

如上面的输出所示,不再需要使Base类的析构函数成为虚拟的,而同时实现虚拟的析构函数的行为。

shared_ptr如何实现这种神奇的行为?

shared_ptr会记住构造期间使用的指针类型。例如,

If you say shared_ptr{ new Derived {} },
then shared_ptr will internally store a Derived*. 
If you say shared_ptr{ new Base {} }, 
then it stores a Base*. 

销毁shared_ptr时,它将在存储的指针上调用delete。自然地,对于非虚拟析构函数,对于Base *,它将调用Base ::〜Base,对于Derived *,它将调用Derived ::〜Derived。
重要事项:

  • 此行为仅通过shared_ptr实现。
  • 通过使用unique_ptr不能实现此行为。
  • STL中的所有类都没有虚拟析构函数,因此,如果要从它们继承,请务必小心。如果要继承,可以在这种情况下使用shared_ptr来应用智能销毁。

例外情况:从Base初始化

考虑以下示例:

// Program to show exception to this behavior while using
// shared_ptr
#include 
#include 
using namespace std;
  
class Base {
public:
    Base()
    {
        cout << "Constructing Base" << endl;
    }
    ~Base()
    {
        cout << "Destructing Base" << endl;
    }
};
  
class Derived : public Base {
public:
    Derived()
    {
        cout << "Constructing Derived" << endl;
    }
    ~Derived()
    {
        cout << "Constructing Derived" << endl;
    }
};
  
int main()
{
    Base* p = new Derived{};
    std::shared_ptr sp{ p };
}

输出:

Constructing Base
Constructing Derived
Destructing Base

在这里,如果shared_ptr是从Base *(这里为“ p”)初始化的,则无法实现这种智能销毁的神奇行为,因为它将调用Base ::〜Base()而不是Derived ::〜Derived()。 shared_ptr将无法找出“ p”所指向的对象的确切类型。因此,在这种情况下,魔术不会发生。

相关文章:

  • C++中的纯虚拟析构函数
  • 在C++中的构造函数/析构函数中调用虚拟方法
要从最佳影片策划和实践问题去学习,检查了C++基础课程为基础,以先进的C++和C++ STL课程基础加上STL。要完成从学习语言到DS Algo等的更多准备工作,请参阅“完整面试准备课程”