有些类的成员函数需要获得自身的std::shared_ptr,但不能就地从this创建,这样会导致多个毫无关系的智能指针引用到同一个对象,导致重复释放【不能传递share_ptr<this>,因为这样会造成2个以上非共享的share_ptr指向同一个对象,未增加引用计数导对象被析构两次】。
std::enable_shared_from_this<>模版类就是解决这个问题。
请看regTo的实现,就需要使用本身的智能指针。
class base : public std::enable_shared_from_this<base>
{
std::string msg;
public:
base(std::string s) : msg(s){}
virtual ~base() = default;
virtual void print()
{
std::cout << msg << std::endl;
}
void regTo(class regObj*);
};
class regObj
{
std::vector<std::shared_ptr<base>> objs;
public:
void regobject(std::shared_ptr<base> shp)
{
objs.push_back(shp);
}
void print()
{
for (auto& c : objs)
c->print();
}
};
void base::regTo(class regObj* p)
{
p->regobject(this->shared_from_this());
}
class concrete1 : public base
{
public:
concrete1(const char* msg) : base(msg){}
};
class concrete2 : public base
{
public:
concrete2(const char* msg) : base(msg) {}
};
int main(int,const char**)
{
auto instance = new regObj;
auto p1 = std::make_shared<concrete1>("concreteObj1");
std::shared_ptr<concreate2> p2(new concrete2("concreteObj2"));
p1->regTo(instance);
p2->regTo(instance);
instance->print();
delete instance;
}
上面regTo函数就需要获得本身的shared_ptr。
注意:调用这个函数的实例必须是构建在shared_ptr上的。因为shared_from_this是从一个weak_ptr构建的一个shared_ptr,这里的weak_ptr是一个shared_ptr弱引用。如果本身没有构建,自然弱引用也是空的。
如果如下所示的使用,则会发生运行时错误:
auto ptr = new concrete2("concreteObj3");
ptr->regTo(instance);
抛出异常的位置在这里:
template<class _Ty2,
enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
explicit shared_ptr(const weak_ptr<_Ty2>& _Other)
{ // construct shared_ptr object that owns resource *_Other
if (!this->_Construct_from_weak(_Other))
{
_THROW(bad_weak_ptr{});
}
}