什么是智能指针?
今天之前我对这个概念也很陌生,但是接触之后我便很喜欢这种指针了。
与其说是指针,不如说是一种基于指针的模板类。
智能指针存在的意义?
俗话说存在即合理,那么这个模板存在的意义是什么?
先看个简单的小栗子:
void testA()
{
a = new testB();
···
return;
}
短短几行,其实问题是很明显的,不过看不出来也正常,因为对大部分功力跟我差不多薄弱的人来说,那个不是错哈。
有没有发现这里只有new,并没有delete。每次调用,该函数都会从堆中申请内存,但是从来没有将内存释放。这样就会导致内存越用越多。
以前我是觉得有没有delete不重要,后来我知道必须要delete了,但是会忘记啊。。。
如果有人觉得为什么会忘记?好,不会忘,那我们再看个小栗子:
a = new testB();
···
if(testC())
{
printf("TestC failed \n");
perror("TestC:");
}
···
delete a;
return;
好,现在记得delete了,那还没来得及delete呢?异常了。
这时候就需要一套智能指针模板,不论发生什么情况,反正它记得自己去delete就好。
这正是auto_ptr、unique_ptr和shared_ptr背后的故事。
这三个指针模板都定义了类似指针的对象,可以将new(直接或间接)的地址赋给这种对象,当智能指针过期时,其析构函数将使用delete来释放内存。
来张图看的比较直观:
上面是auto_ptr的示例,另外两个也是一样的。
那怎么用呢?
要创建智能指针对象,首先要包它们的头文件memory.
然后看一下代码格式:
#include<memory>
//原:
string *ptr = new string;
//改
std::auto_ptr<std::string> ptr(new string);
另外两个也是这种格式
注意到这些模板是位于名空间std中的。
所有智能指针类都有一个explicit构造函数,所以不应该直接对这些指针类执行复制赋值,如下:
shared_ptr<double> pd;
double *pdd = new double;
pd = pdd; //这个是不允许的
pd = shared_ptr<double> (pdd); //上面那个改成这样
shared_ptr<double> ps = pdd; //这样也是不允许的
shared_ptr<double> ps(pss); //上面那个改成这样
接下来来看一个三种模板都应该避免的情况,其实前面的篇章也讲过了,就是将局部变量的地址传入堆区。
string str;
shared_ptr<string> sstr(&str);
这是明显错误的,该函数结束的时候,作为局部变量的str会被释放,但是sstr不会。
有关智能指针的注意事项:
- List item
首先,我们把auto_ptr摈弃掉。
因为它比较老,允许多个指针指向同一个变量。
那么回收的时候就会出现一个问题:一个变量被回收了多次。
那肯定是不允许的。
shared_ptr通过技术手段解决了这个析构的问题,unique_ptr则不允许将多个指针指向一个变量,它会在编译的时候直接报错。
- List item
相比另外两种模板,unique还有一种支持数组指针的变体。
std::unique_ptr<double[]> dbo(new double[5]);
- List item
综上分析可得,shared_ptr支持指针数组,unique_ptr支持数组指针。
-
List item
不要将 *this指针交给智能指针。 -
List item
不要在函数实参中创建shared_ptr
function (shared_ptr (new int),g());//有缺陷
正确的写法应该是先创建智能指针: shared_ptr p(new int()); f(p,g());
什么时候释放智能指针?
这应该也是比较关心的问题吧。
指针的作用域结束时它就自己清理了。至于如果有人非要手动去释放,那我个人建议你用普通指针。