using msgCallback = std::function<void()>;
class A {
public:
~A() {
cout << "A::~A()" << endl;
}
void output() {
cout << "A::output()" << endl;
}
};
class B {
public:
~B() {
cout << "B::~B()" << endl;
}
void setCallback(const msgCallback& cb) {
if (m_cb == nullptr)
m_cb = cb;
}
void resetCallback() {
m_cb = nullptr;
}
private:
msgCallback m_cb;
};
A未能按预期析构:
int main()
{
shared_ptr<B> spb = make_shared<B>();
{
shared_ptr<A> spa = make_shared<A>(); //use_count:1
list<shared_ptr<A>> lst;
lst.push_back(spa); //use_count:2
cout << "count1: " << spa.use_count() << endl;
{
std::function<void()> f = std::bind(&A::output, spa); //use_count:3
spb->setCallback(f); //use_count:4
cout << "count2: " << spa.use_count() << endl;
} //use_count:3
cout << "count3: " << spa.use_count() << endl;
if (!lst.empty())
lst.erase(lst.begin()); //use_count:2
cout << "count4: " << spa.use_count() << endl;
} //use_count:1
//期望spa在lst.erase后就析构
//结果spb->m_cb还具有spa的一份引用,导致A不能按预期析构
system("pause");
return 0;
}
A正常析构:
int main()
{
{
shared_ptr<A> spa = make_shared<A>(); //use_count:1
shared_ptr<B> spb = make_shared<B>();
list<shared_ptr<A>> lst;
lst.push_back(spa); //use_count:2
cout << "count1: " << spa.use_count() << endl;
{
std::function<void()> f = std::bind(&A::output, spa); //use_count:3
spb->setCallback(f); //use_count:4
cout << "count2: " << spa.use_count() << endl;
} //use_count:3
cout << "count3: " << spa.use_count() << endl;
if (!lst.empty())
lst.erase(lst.begin()); //use_count:2
cout << "count4: " << spa.use_count() << endl;
spb->resetCallback(); //use_count:1
cout << "count5: " << spa.use_count() << endl;
} //use_count:0
system("pause");
return 0;
}
当std::bind绑定shared_ptr时,shared_ptr引用计数加一,
这时候认为function f保持一份引用,只有f析构了引用计数才减一
当我将function传给B::m_cb时,B::m_cb保持一份引用
所以要想spa在list::erase的时候析构,必须提前将spb_m_cb重置为nullptr
但是这样就对A的生命周期管理造成了负担。
所以当我们想要准确的控制对象的生命周期的时候,用裸指针可能更合适。
还有一种情况用裸指针可能好点,例如TcpConnection类和Channel类:
如果用shared_ptr互相包含,可能会出现智能指针循环引用的情况。
而用裸指针,可以很方便的控制Channel在TcpConnection析构前析构。
如果真的要用shared_ptr管理对象生命周期,那就让shared_ptr的引用计数保持为1,也就是让某个对象具有这个shared_ptr实例,
其它地方全部传shared_ptr的引用。当这个对象析构了,shared_ptr就随之析构。
还有一点:为了避免引用计数增加,我们用std::bind绑定指针的时候,可以直接传this指针,而不是shared_ptr。
为了避免shared_ptr的循环引用,可以用weak_ptr