shared_ptr
shared_ptr 是一个标准的共享所有权的智能指针,允许多个指针指向同一个对象,定义在 memory 文件中,命名空间为 std。shared_ptr最初实现于Boost库中,后由 C++11 引入到 C++ STL。shared_ptr 利用引用计数的方式实现了对所管理的对象的所有权的分享,即允许多个 shared_ptr 共同管理同一个对象。
shared_ptr 的基本用法
#include <iostream>
#include <memory>
using namespace std;
class MyClass
{
public:
MyClass()
{
cout << "MyClass" << endl;
}
~MyClass()
{
cout << "~MyClass" << endl;
}
private:
};
void safeDelete(MyClass* p)
{
if (p)
{
cout << "safeDelete" << endl;
delete p;
}
}
int main()
{
//创建空的shared_ptr
shared_ptr<int> m1 = make_shared<int>();
cout << "m1.use_count: " << m1.use_count() << endl;
//利用原始指针创建shared_ptr 对象
shared_ptr<int> m2(new int);
cout << "m2.use_count: " << m2.use_count() << endl;
//分离关联的原始指针,引用计数减1
m2.reset();
cout << "m2.use_count after reset: " << m2.use_count() << endl;
//重置m2的内部指针,引用计数加1
m2.reset(new int(2));
cout << "m2.use_count after reset(new int): " << m2.use_count() << endl;
//自定义删除器
shared_ptr<MyClass> m3(new MyClass, safeDelete);
m3.reset();
return 0;
}
shared_ptr的注意事项
不使用同一个原始指针构造 shared_ptr
假如使用原始指针myclass
创建了p1,又同样方法创建了p2,当p1超出作用域时会调用myclass的析构函数,此时myclass成了悬空指针,当p2超出作用域会再次调用myclass的析构函数。
MyClass* myclass = new MyClass();
if (true)
{
shared_ptr<MyClass> p1(myclass);
shared_ptr<MyClass> p2(myclass);
}
不使用栈中的指针构造 shared_ptr 对象
shared_ptr 默认的构造函数中使用的是delete
来删除关联的指针,所以构造的时候也必须使用new
出来的堆空间的指针。
MyClass myclass;
shared_ptr<MyClass> m4(&myclass);//error
weak_ptr
share_ptr虽然已经很好用了,但是有一点share_ptr智能指针还是有内存泄露的情况,当两个对象相互使用一个shared_ptr成员变量指向对方,会造成循环引用,使引用计数失效,从而导致内存泄漏。
weak_ptr 是一种不控制对象生命周期的智能指针, 它指向一个 shared_ptr 管理的对象. 进行该对象的内存管理的是那个强引用的shared_ptr, weak_ptr只是提供了对管理对象的一个访问手段。weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。weak_ptr是用来解决shared_ptr相互引用时的死锁问题,如果说两个shared_ptr相互引用,那么这两个指针的引用计数永远不可能下降为0,资源永远不会释放。它是对对象的一种弱引用,不会增加对象的引用计数,和shared_ptr之间可以相互转化,shared_ptr可以直接赋值给它,它可以通过调用lock函数来获得shared_ptr。
#include <iostream>
#include <memory>
using namespace std;
class MyClass
{
public:
MyClass()
{
cout << "MyClass()" << endl;
}
~MyClass()
{
cout << "~MyClass()" << endl;
}
private:
};
int main()
{
shared_ptr<MyClass> myclass_ptr(new MyClass);
cout << "myclass_ptr.use_count: " << myclass_ptr.use_count() << endl;
//创建空 weak_ptr
weak_ptr<MyClass> w;
//与 shared_ptr 指向相同的对象,shared_ptr 引用计数不变
weak_ptr<MyClass> w2(myclass_ptr);
cout << "w2.use_count: " << w2.use_count() << endl;
//赋值后 w 与 myclass_ptr 共享对象
w = myclass_ptr;
cout << "myclass_ptr.use_count: " << myclass_ptr.use_count() << " w.use_count: " << w.use_count() << endl;
//将 w 置空
w.reset();
cout << "myclass_ptr.use_count after w.reset: " << myclass_ptr.use_count() << " w.use_count: " << w.use_count() << endl;
//w.expired(): 若 w.use_count() 为 0,返回 true,否则返回 false
//w.lock(): 如果 expired() 为 true,返回一个空 shared_ptr,否则返回非空 shared_ptr
shared_ptr<MyClass> p = w.lock();
cout << " w.expired: " << w.expired() << " w.lock: " << p << endl;
w = w2;
p = w.lock();
cout << " w.expired: " << w.expired() << " w.lock: " << p << endl;
return 0;
}
weak_ptr 的作用
如下测试程序,A 和 B 存在相互引用,导致内存无法释放:
class B;
class A {
public:
A()
{
cout << "A::A()" << endl;
}
~A()
{
cout << "A::~A()" << endl;
}
void setbPtr(shared_ptr<B> p)
{
_bPtr = p;
}
private:
shared_ptr<B> _bPtr;
};
class B {
public:
B()
{
cout << "B::B()" << endl;
}
~B()
{
cout << "B::~B()" << endl;
}
void setaPtr(shared_ptr<A> p)
{
_aPtr = p;
}
private:
shared_ptr<A> _aPtr;
};
int main()
{
//weak_ptr_test();
shared_ptr<A> a(new A);
shared_ptr<B> b(new B);
a->setbPtr(b);
b->setaPtr(a);
return 0;
}
在A和 B 中 将 shared_ptr 修改为 weak_ptr 弱引用的智能指针,由于weak_ptr 对象引用资源时不会增加引用计数,所以可以正常的释放内存,修改后的测试程序如下:
class B;
class A {
public:
A()
{
cout << "A::A()" << endl;
}
~A()
{
cout << "A::~A()" << endl;
}
void setbPtr(shared_ptr<B> p)
{
_bPtr = p;
}
private:
weak_ptr<B> _bPtr;
};
class B {
public:
B()
{
cout << "B::B()" << endl;
}
~B()
{
cout << "B::~B()" << endl;
}
void setaPtr(shared_ptr<A> p)
{
_aPtr = p;
}
private:
weak_ptr<A> _aPtr;
};
shared_ptr和weak_ptr的核心实现
weakptr的作为弱引用指针,其实现依赖于counter的计数器类和share_ptr的赋值,构造,所以先把counter和share_ptr简单实现
Counter简单实现
class Counter
{
public:
Counter() : s(0), w(0){};
int s; //share_ptr的引用计数
int w; //weak_ptr的引用计数
};
counter对象的目地就是用来申请一个块内存来存引用基数,s是share_ptr的引用计数,w是weak_ptr的引用计数,当w为0时,删除Counter对象。
share_ptr的简单实现
template <class T>
class WeakPtr; //为了用weak_ptr的lock(),来生成share_ptr用,需要拷贝构造用
template <class T>
class SharePtr
{
public:
SharePtr(T *p = 0) : _ptr(p)
{
cnt = new Counter();
if (p)
cnt->s = 1;
cout << "in construct " << cnt->s << endl;
}
~SharePtr()
{
release();
}
SharePtr(SharePtr<T> const &s)
{
cout << "in copy con" << endl;
_ptr = s._ptr;
(s.cnt)->s++;
cout << "copy construct" << (s.cnt)->s << endl;
cnt = s.cnt;
}
SharePtr(WeakPtr<T> const &w) //为了用weak_ptr的lock(),来生成share_ptr用,需要拷贝构造用
{
cout << "in w copy con " << endl;
_ptr = w._ptr;
(w.cnt)->s++;
cout << "copy w construct" << (w.cnt)->s << endl;
cnt = w.cnt;
}
SharePtr<T> &operator=(SharePtr<T> &s)
{
if (this != &s)
{
release();
(s.cnt)->s++;
cout << "assign construct " << (s.cnt)->s << endl;
cnt = s.cnt;
_ptr = s._ptr;
}
return *this;
}
T &operator*()
{
return *_ptr;
}
T *operator->()
{
return _ptr;
}
friend class WeakPtr<T>; //方便weak_ptr与share_ptr设置引用计数和赋值
protected:
void release()
{
cnt->s--;
cout << "release " << cnt->s << endl;
if (cnt->s < 1)
{
delete _ptr;
if (cnt->w < 1)
{
delete cnt;
cnt = NULL;
}
}
}
private:
T *_ptr;
Counter *cnt;
};
share_ptr的给出的函数接口为:构造,拷贝构造,赋值,解引用,通过release来在引用计数为0的时候删除_ptr和cnt的内存。
weak_ptr简单实现
template <class T>
class WeakPtr
{
public: //给出默认构造和拷贝构造,其中拷贝构造不能有从原始指针进行构造
WeakPtr()
{
_ptr = 0;
cnt = 0;
}
WeakPtr(SharePtr<T> &s) : _ptr(s._ptr), cnt(s.cnt)
{
cout << "w con s" << endl;
cnt->w++;
}
WeakPtr(WeakPtr<T> &w) : _ptr(w._ptr), cnt(w.cnt)
{
cnt->w++;
}
~WeakPtr()
{
release();
}
WeakPtr<T> &operator=(WeakPtr<T> &w)
{
if (this != &w)
{
release();
cnt = w.cnt;
cnt->w++;
_ptr = w._ptr;
}
return *this;
}
WeakPtr<T> &operator=(SharePtr<T> &s)
{
cout << "w = s" << endl;
release();
cnt = s.cnt;
cnt->w++;
_ptr = s._ptr;
return *this;
}
SharePtr<T> lock()
{
return SharePtr<T>(*this);
}
bool expired()
{
if (cnt)
{
if (cnt->s > 0)
{
cout << "empty" << cnt->s << endl;
return false;
}
}
return true;
}
friend class SharePtr<T>; //方便weak_ptr与share_ptr设置引用计数和赋值
protected:
void release()
{
if (cnt)
{
cnt->w--;
cout << "weakptr release" << cnt->w << endl;
if (cnt->w < 1 && cnt->s < 1)
{
//delete cnt;
cnt = NULL;
}
}
}
private:
T *_ptr;
Counter *cnt;
};
以上参考:
- https://www.cnblogs.com/WindSun/p/11444429.html
- https://www.cnblogs.com/greatverve/p/smart-ptr.html
- https://www.cnblogs.com/lanxuezaipiao/p/4132096.html
- https://www.cnblogs.com/TianFang/archive/2008/09/20/1294590.html
- https://blog.csdn.net/nicolasyan/article/details/50588022
- https://blog.csdn.net/shanno/article/details/7363480
- https://blog.csdn.net/k346k346/article/details/81478223