shared_ptr
shared_ptr是一种共享型的智能指针,它使用一种“引用计数”的机制来让它变得“智能”。考虑这样一个过程:
- 假设有一个叫pA的shared_ptr,创建它的时候引用计数为1;
- 当有另一个pA2=pA时,查看pA和pA2的引用计数都变成了2;
- 而当pA2离开函数作用域时,pA的计数又回到了1;
- 当pA也离开自己的作用域时,计数则变为0,此时指针所指向的内存就会被销毁。
下面的例子中则体现了这个过程
#include <iostream>#include <memory>using namespace std;struct A{string m_strA;A(string strA){m_strA = strA;cout << "A(" << m_strA << ")" << endl;}~A(){cout << "~A(" << m_strA << ")" << endl;}};void PrintSharedA(string strObj, shared_ptr<A>& pA){cout << strObj << " 引用计数:" << pA.use_count() << endl;}void TestShared(){cout << "创建一个共享指针 pA" << endl;shared_ptr<A> pA = make_shared<A>("1");PrintSharedA("pA", pA);cout << "令pA2 = pA;" << endl;shared_ptr<A> pA2 = pA;PrintSharedA("pA", pA);PrintSharedA("pA2",pA2);}int main(int argc, char *argv[]) {TestShared();}
unique_ptr
unique_ptr是一种独占型指针,相比于shared_ptr要轻量级许多,它即便没有引用计数的机制,但也可以在离开作用域后自动的销毁内存,因为它每次只允许一个指针实例拥有它(你可以把它想象成)。
假设我们定义了下面的一个结构:
struct A{int m_iA;string m_strA;A(int iA, int strA){m_iA = iA;m_strA = strA;}};
然后我们使用以下代码创建一个独占指针:
unique_ptr<A> pA = make<A>(1, "1");//使用工厂方法创建指向A的独占指针
当我们想要向下面的代码这样将pA赋值给pB的时候,则会编译错误,因为独占指针不允许两个指针指向同一个实例
unique_ptr<A> pA2 = pA;//错误,不能复制
想要实现类似的操作,你可以通过以下的方式“折衷”的完成
unique_ptr<A> pA2 = std::move(pA); //将pA的所有权转移给pB,这时候你会发现pA变成了nullptr
shared_ptr的循环引用异常现象
考虑到下面这种异常情景:
- 有一对成为了情侣的结构指针,它们叫pBoy和pGirl
- 另外它们有着相互指向对方的指针,pBoy下有个pGirl的共享指针,pGirl下面也有个pBoy的共享指针
- 这时当它们互相指向时,离开作用域后它们互相的引用计数并不会减少,导致无法析构
具体看下面这个例子:
#include <iostream>#include <memory>using namespace std;struct Boy;struct Girl;struct Boy{shared_ptr<Girl> pGirl;string m_str;Boy(string str){m_str = str;cout << "Boy(" << m_str << ")" << endl;}~Boy(){cout << "~Boy(" << m_str << ")" << endl;}friend ostream &operator<<(ostream &output, const Boy& stuBoy){output << "Boy(" << stuBoy.m_str << ")";return output;}};struct Girl{shared_ptr<Boy> pBoy;string m_str;Girl(string str){m_str = str;cout << "Girl(" << m_str << ")" << endl;}~Girl(){cout << "~Girl(" << m_str << ")" << endl;}friend ostream &operator<<(ostream &output, const Girl& stuGirl){output << "stuGirl(" << stuGirl.m_str << ")";return output;}};template<class T>void PrintShared(string strObj, shared_ptr<T>& pT){cout << strObj << " 引用计数:" << pT.use_count() << endl;}void TestShared2(){auto pBoy = make_shared<Boy>("boy");auto pGirl = make_shared<Girl>("girl");PrintShared("pBoy", pBoy);PrintShared("pGirl", pGirl);pBoy->pGirl = pGirl;PrintShared("pBoy", pBoy);PrintShared("pGirl", pGirl);pGirl->pBoy = pBoy;PrintShared("pBoy", pBoy);PrintShared("pGirl", pGirl);}int main(int argc, char *argv[]) {TestShared2();}
weak_ptr
为了克服以上shared_ptr循环引用情况下的异常,weak_ptr则是被设计出来监视shared_ptr的,言下之意它并不是一个单独使用的指针,而是配合shared_ptr一起使用的。
参考:
- 《深入应用C++11 代码优化与工程级应用》
