1. shared_ptr
shared_ptr 是c++ 管理资源的利器,也是C++ 相对于其他语言最大区别的RAII特性的最直观体现。
shared_ptr一大好处是其创建时即捕获析构动作,即使基类析构函数不是虚函数,也能正确完成子类与析类的析构动作。如下:
class Base
{
public:
~Base()
{
std::cout << "Base destructor" << std::endl;
}
};
class Derived : public Base
{
public:
~Derived()
{
std::cout << "Derived destructor" << std::endl;
}
};
void virtual_destructor()
{
{
std::cout << "--------------------" << std::endl;
std::shared_ptr<Base> sharedA(new Derived);
}
std::cout << "--------------------" << std::endl;
Base * a = new Derived;
delete a;
}
Output:
--------------------
Derived destructor
Base destructor
--------------------
Base destructor
对比可见,由于基类析构函数不是虚函数,因此对基类原生指针的析构,并未正确的析构子类。而利用shared_ptr则完成正确动作。
2.原理
以下代码模拟shared_ptr的析构原理。
template <typename T>
class simple_ptr_internal_interface {
public:
virtual T* get() = 0;
virtual void destruct() = 0;
}; // class simple_ptr_internal_interface
template <typename T, typename D>
class simple_ptr_internal: public simple_ptr_internal_interface {
public:
simple_ptr_internal(T* p, D d): pointer(p), deleter(std::move(d)) {}
virtual T* get() override { return pointer; }
virtual void destruct() override { deleter(pointer); }
private:
T* pointer;
D deleter;
}; // class simple_ptr_internal
template <typename T>
class simple_ptr {
template <typename U>
struct DefaultDeleter {
void operator()(T* t) { delete static_cast<U*>(t); }
};
template <typename Derived>
using DefaultInternal = simple_ptr_internal<T, DefaultDeleter<Derived>>;
public:
template <typename Derived>
simple_ptr(Derived* d): internal(new DefaultInternal<Derived>{d}) {}
~simple_ptr() { this->destruct(); }
private:
void destruct() { internal->destruct(); }
simple_ptr_internal_interface* internal;
};
从以上代码可见,shared_ptr在创建时实际保存了所创建的子类类型的指针,并在最终删除对象时在删除器中调用。因此,可正确的析构子类与基类。