继前一篇:
shared_pr会出现循环以来造成悬挂指针。另外一个问题则是:必须确保某个对象只被一组shared pointer拥有。示例一个错误代码:
int * p = new int; shared_ptr<int> sp1(p); shared_ptr<int> sp2(p); //ERROR:two shared pointers manage allocated int
问题在于sp1和sp2都拥有释放权,这会导致两次delete。因此应该直接在创建对象和资源的时候即刻设置smart pointer:
shared_ptr<int> sp1(new int); shared_ptr<int> sp2(sp1);
这个问题可能间接发生,根据上一节的例子,准备为Person引入一个成员函数,用来建立“从kid指向parent” 的reference 及其反向reference:
shared_ptr<Person> mom(new Person(name + "'s mom")); shared_ptr<Person> dad(new Person(name + "'s dad")); shared_ptr<Person> kid(new Person(name, mom, dad)); kid->setParentsAndTheirKids(mom, dad); //下面是一个错误的直观版本 class Person{ public: //.... void setParentAndTheirKids(shared_ptr<Person> m = nullptr, shared_ptr<Person> f = nullptr) { mother = m; father = f; if(m != nullptr){ m->kids.push_back(shared_ptr<Perrson>(this));} //ERROR if(f != nllptr){ f->kids.push_back(shared_ptr<Person>(this));} //ERROR //.... } };
问题出在this的那个shared pointer 的建立。之所以那么做是为了设置mother 和 father两个成员的kids。但是为了那么做,需要一个shared pointer指向kid,而我们没有 。然而,根据this建立一个新的shared pointer不能解决问题,因为这么一来就是开启了新的拥有者团队(a new group of owners)。
对付这个问题的办法之一就是,将指向kid的那个shared pointer传递为第三实参。但c++标准库提供了另外一个选项:class std::enable_shared_from_this<> 。
你可以从class std::enable_shared_from_this<> 派生自己的class,表现出被shared pointer管理的对象,做法是将class 名称当做template是实参传入。
然后可以使用一个派生的成员函数 shared_from_this() 建立一个源自this的正确shared_ptr。
class Person : public std::enable_shared_from_this<Person>{ public: //.... void setParentAndTheirKids(shared_ptr<Person> m = nullptr, shared_ptr<Person> f = nullptr) { mother = m; father = f; if(m != nullptr){ m->kids.push_back(shared_from_this());} //Ok if(f != nllptr){ f->kids.push_back(shared_from_this());} //OK //.... } };
但shared_form_this 不能放在构造函数中,因为在Person构造结束之前,shared_ptr本身被存放在Person的基类中,也就是enable_shared_from_this<>内部的一个private成员中。所以,在构造期间,绝对无法建立shared pointer的循环引用。