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 代码优化与工程级应用》