1、问题引入
在C++中,静态内存和栈内存外,还有一部分内存称为堆程序用堆来存储动态分配的对象即那些在程序运行时分配的对象,当动态对象不再使用时,我们的代码必须显式的销毁它们。在C++中一般使用“new”:在动态内存中为对象分配一块空间并返回一个指向该对象的指针,“delete”:指向一个动态独享的指针,销毁对象,并释放与之关联的内存。
动态内存管理经常会出现两种问题:一种是忘记释放内存,会造成内存泄漏;一种是尚有指针引用内存的情况下就释放了它,就会产生引用非法内存的指针。
为了更加容易(更加安全)的使用动态内存,引入了智能指针的概念。智能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象。C++中常用的智能指针有shared_ptr(多个指针指向同一对象)、unique_ptr(独占所指的对象)、weak_ptr(伴随类,弱引用)、auto_ptr(局部指针C++11已弃用),位于头文件memory中。实际上智能指针还有boost::scoped_ptr()、boost::scoped_array、boost::shared_array等。
2、shared_ptr类
shared_ptr允许多个指针指向同一对象,资源可以被多个指针所共享。创建智能指针时必须提供额外的信息,指针可以指向的类型:
shared_ptr<string> p1;
shared_ptr<list<int>> p2;
默认初始化的智能指针中保存着一个空指针。 智能指针的使用方式和普通指针类似,解引用一个智能指针返回它指向的对象,在一个条件判断中使用智能指针就是检测它是不是空。
if(p1 && p1->empty()){
*p1 = "hi"; // 如果p1指向一个空string,解引用p1,将一个新值赋予string
}
(1)shared_ptr的操作
如下表所示是shared_ptr和unique_ptr都支持的操作:
如下表所示是shared_ptr特有的操作:
注:make_shared函数:
最安全的分配和使用动态内存的方法就是调用一个名为make_shared的标准库函数,此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。头文件和share_ptr相同,在memory中必须指定想要创建对象的类型,定义格式见下面例子:
shared_ptr<int> p3 = make_shared<int>(42);
shared_ptr<string> p4 = make_shared<string>(10,'9');
shared_ptr<int> p5 = make_shared<int>();
make_shared用其参数来构造给定类型的对象,如果我们不传递任何参数,对象就会进行值初始化。
(2)shared_ptr的拷贝和赋值
当进行拷贝和赋值时,每个shared_ptr都会记录有多少个其他shared_ptr指向相同的对象。
auto p = make_shared<int>(42);
auto q(p);
可以认为每个shared_ptr都有一个关联的计数器,通常称其为引用计数,无论何时我们拷贝一个shared_ptr,计数器都会递增。当我们给shared_ptr赋予一个新值或是shared_ptr被销毁(例如一个局部的shared_ptr离开其作用域)时,计数器就会递减,一旦一个shared_ptr的计数器变为0,它就会自动释放自己所管理的对象。
auto r = make_shared<int>(42);//r指向的int只有一个引用者
r=q;//给r赋值,令它指向另一个地址
//递增q指向的对象的引用计数
//递减r原来指向的对象的引用计数
//r原来指向的对象已没有引用者,会自动释放
总结:引用计数