众所周知,在C++11以前,C++的内存释放是众多程序员头疼的问题,这也是导致使用C++开发效率低下的原因之一,为此C++11引入了智能指针这个概念。
原理
智能指针实际上采用引用计数的方法,调用构造函数时,引用计数默认初始化为1,每一个对象负责维护对象所有引用的计数值。当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减。当引用计数到零时,该对象就将释放占有的资源。
实现
在C++11中,智能指针采用类模板,该类模板包含了一个引用计数的类。程序员定义的每个类,编译器就会让该类继承引用计数的类。代码实现:
class RefCount {
public:
RefCount():crefs(0) {}
virtual ~RefCount() {}
void upCount() {
++crefs;
}
void downCount() {
if(--crefs == 0)
delete this;
}
private:
int crefs;
};
template<typename T>
class SmartPtr{
public:
SmartPtr(T* p): ptr(p) {
ptr->upCount();
}
~SmartPtr() {}
T* operator ->() const {
return ptr;
}
T& operator *() const {
return *ptr;
}
SmartPtr& operator =(T* p) {
ptr->downCount();
p->upCount();
ptr = p;
return *this;
}
SmartPtr(const SmartPtr<T>& p) {
ptr = p;
ptr->upCount();
}
operator T*() const {
return ptr;
}
SmartPtr& operator = (SmartPtr<T>& p) {
return operator =((T*)p);
}
private:
T* ptr;
};
C++11中的 智能指针
share_ptr 允许多个指针指向同一个对象;
unique_ptr 则单独占有一个对象;
weak_ptr 是一种弱引用, 指向 share_ptr 所管理的对象。
推荐使用make_shared 而不是 new
使用make_shared就能在分配对象的同时将 shared_ptr 与之绑定,从而避免无意中将同一内存绑定到多个独立创建的shared_ptr 上
weak_ptr可以用来解决循环引用
因为 weak_ptr 是弱引用,weak_ptr 的构造和析构不会导致引用计数的增加或者减少
例如:
#include <iostream>
#include <memory>
using namespace std;
class B;
class A {
public:
shared_ptr<B> pb;
//weak_ptr<B> pb;
A() {
cout << "construct A " << endl;
}
~A() {
cout << "deconstruct A" << endl;
}
};
class B {
public:
shared_ptr<A> pa;
//weak_ptr<A> pa;
B() {
cout << "construct B" << endl;
}
~B() {
cout << "deconstruct B" << endl;
}
};
int main() {
shared_ptr<A> ptrA(new A());
shared_ptr<B> ptrB(new B());
cout << ptrA.use_count() << endl;
cout << ptrB.use_count() << endl;
ptrA->pb = ptrB;
ptrB->pa = ptrA;
cout << ptrA.use_count() << endl;
cout << ptrB.use_count() << endl;
return 0;
}
如果使用 share_ptr 在构造函数内,结果将输出
construct A
construct B
1
1
2
2
并没有调用析构函数,导致内存泄漏
如果使用 weak_ptr 在构造函数内,结果将输出
construct A
construct B
1
1
1
1
deconstruct B
deconstruct A
正确调用析构函数,内存被全部释放