智能指针 smart ptr
智能指针的目的在于利用栈会被程序自动销毁的特性来进行内存管理,
避免内存泄漏问题,也就是用栈来管理堆.
C++标准中的智能指针包括
std::auto_ptr(C++98),std::shared_ptr(C++11),std::unique_ptr(c++11),std::weak_ptr(c++11)
除去标准之外,还有一些比如scoped_ptr(boost)在boost中实现 但没有引入标准中.
智能指针的共同特点
和智能指针使用相关的重要概念是作用域.
C/C++中的作用域表明变量的生存周期,一般用花括号表征.
函数中的栈变量的作用域就是这个函数的函数体内,
类的变量成语的作用域就是类的生存周期,类被构造时创建,析构时销毁.
所以智能指针的使用场景常常是这样的:
1. 在函数中作为栈变量
void test() {
scoped_ptr<int> aa(new int[10]);
}
aa指向一块大小为sizeof(int)*10的内存,当test函数退出时动态申请的数组内存被销毁.
2. 类内部作为变量
class test {
public:
test() {
ptr.reset(new int[10]);
}
private:
scoped_ptr<int> ptr;
};
当test类的对象被销毁时,分配的数组内存也随之被销毁.
智能指针的reset和release
reset使智能指针指向某个对象
简单实现:
void reset(T* ptr) {
mPtr = ptr;
}
release则是解除智能指针对所指向对象的引用
T* release() {
T* tmp = mPtr;
mPtr = nullptr; //不删除指向的对象 因为release只是解引用
return tmp;
}
auto_ptr
++,.
unique_ptr
unique_ptr的特性是独占指向的对象
当unique_ptr指向某个对象后,其余的unique_ptr不能直接通过浅拷贝或是拷贝构造这个unique_ptr来得到对象的引用.
这个禁止拷贝的特性是通过重载来实现的:
private:
unique_ptr(const unique_ptr &);
unique_ptr&operator=(const unique_ptr &);
重载=操作符和将拷贝构造声明为private方法 其余unique_ptr对象就不能拷贝它了.
unique_ptr本身是独占的 但不代表这个对象也是独占的
void test() {
int *p = new int;
unique_ptr<int> a(p);
unique_ptr<int> b(p);
}
这样的引用 在test函数退出时会引发free错误 因为两次释放了同一个对象
shared_ptr和weak_ptr
shared_ptr的特性是引用计数
当程序退出指针所在的作用域时,假如shared_ptr的引用计数大于1,则不会释放智能指针指向的对象.
利用这个特性,可以使得多个shared_ptr引用同一个对象,让最后一个使用者来释放对象.
shared_ptr的这个特性可能导致环回引用,导致对象永远释放不了.
weak_ptr就是为了解决这一特性出现的.
环形引用也就是两个类交叉引用了对方的shared_ptr
class Parent
{
public:
shared_ptr<Child> child;
};
class Child
{
public:
shared_ptr<Parent> parent;
};
shared_ptr<Parent> pA(new Parent);
shared_ptr<Child> pB(new Child);
pA->child = pB;
pB->parent = pA;
这样做导致pA和pB的引用计数都为2 由于指针指向的对象不会被释放,所以引用计数始终等于2,出作用域时无法释放
碰到这种情况,将可能出现环形引用的shared_ptr替换一个为weak_ptr就可以了.