一、当然在某些情况下,shared_ptr有可能造成循环引用,这样就造成了shared_ptr的引用次数一直大于0,也就不可能去释放该指针,也就造成了传说中的内存泄漏。等下,我们想想,我们起始使用智能指针的的目的就是防止内存泄漏,而循环引用又必然造成内存泄漏。说到这里,我们回顾我们这一节的题目weak_ptr,对滴,为了解决该问题,我们的标准库又引入了另外一个智能指针weak_ptr。
考虑一下下面这种情况
#include
#include
#include
#include
using namespace std;
class Person {
public:
string name;
shared_ptr mother;
shared_ptr father;
vector> kids;
Person (const string& n,shared_ptr m = nullptr,shared_ptr f = nullptr)
: name(n), mother(m), father(f) {
}
~Person()
{
cout << "delete " << name << endl;
}
};
shared_ptr initFamily (const string& name)
{
shared_ptr mom(new Person(name+"’s mom"));
shared_ptr dad(new Person(name+"’s dad"));
shared_ptr kid(new Person(name,mom,dad));
mom->kids.push_back(kid);
dad->kids.push_back(kid);
return kid;
}
int main()
{
shared_ptr p = initFamily("nico");
cout << "nico’s family exists" << endl;
cout << "- nico is shared " << p.use_count() << " times" << endl;
cout << "- name of 1st kid of nico’s mom: "
<< p->mother->kids[0]->name << endl;
p = initFamily("jim");
cout << "jim’s family exists" << endl;
}
在上面这个例子里,每调用一个initFamily就会生成三个对象,而其中儿子存在于父母的kids列表中,儿子中又有父母的引用,这样就造成了,无法释放该资源。
为了解决该问题,我们可以将
vector
这样就解决了程序中的循环引用。
weak_ptr对shared_ptr管理的对象存在弱引用。如果要访问weak_ptr引用的对象,须将weak_ptr转换为shared_ptr。
使用weak_ptr
注意:如果使用weak_ptr时不能确保shared_ptr中的资源是否已经释放,我们可以使用以下几种方式来确保该问题的发生。
1. 使用expired(),如果该对象已经被释放,则返回true(与使用use_count一样)
2. 使用shared_ptr的构造函数将weak_ptr转换为shared_ptr,然后使用,如果已经被释放了,则weak_ptr将抛出bad_weak_ptr这个标准异常。
3. 使用use_count(),但是这个标准库指出“use_count() is not necessarily efficient.”
二、使用shared_ptr时要注意这种情况:
int* p = new int;
shared_ptr sp1(p);
shared_ptr sp2(p);
在这种情况下,sp1,与sp2都能释放p的资源,当sp1释放了资源之后,sp2在次释放则会出现异常,所以通常情况下,我们new 一个对象之后,立即创建一个智能指针管理该对象。
例如:
shared_ptr sp1(new int);
shared_ptr sp2(sp1); // OK
三、看下面这段代码
class Person {
public:
...
void setParentsAndTheirKids (shared_ptr m = nullptr,
shared_ptr f = nullptr)
{
mother = m;
father = f;
if (m != nullptr)
{
m->kids.push_back(shared_ptr(this)); // ERROR
}
if (f != nullptr)
{
f->kids.push_back(shared_ptr(this)); // ERROR
}
}
...
};
在上面这个例子里,不能将this转换成shared_ptr,因为这样会有两组shared_ptr共同使用这个对象,就会造成上面提到的那个为题,这的资源将会被释放两次会引起异常。
可是怎么解决这个问题呢:
1. 在这个函数声明中再添加一个shared_ptr指针作为第三个参数。
2. 利用标准库提供的std::enable_shared_from_this
使用std::enable_shared_from_this:
class Person : public std::enable_shared_from_this
{
public:
...
Person (const string& n,
shared_ptr m = nullptr,
shared_ptr f = nullptr)
: name(n), mother(m), father(f)
{
if (m != nullptr)
{
m->kids.push_back(shared_from_this());
}
if (f != nullptr)
{
f->kids.push_back(shared_from_this());
}
}
...
};
这里有一个需要注意的地方,那就是不能在构造函数中使用shared_from_this。
使用shared_from_this();函数时,该类需要从enable_shared_from_this
当需要转换指针时,用普通的static_cast不行,必须使用static_pointer_casrt;
例如:
auto p1 = shared_ptr
auto p2 = static_pointer_cast
五、共享计数器
struct A
{
int *n;
}
std::shared_ptr pA();
auto pN = std::shared_ptr(pA,pA->n);
cout<