C++ 智能指针

什么是智能指针?

今天之前我对这个概念也很陌生,但是接触之后我便很喜欢这种指针了。
与其说是指针,不如说是一种基于指针的模板类。

智能指针存在的意义?

俗话说存在即合理,那么这个模板存在的意义是什么?
先看个简单的小栗子:

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来释放内存。

来张图看的比较直观:
C++ 智能指针

上面是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不会。


有关智能指针的注意事项:

  1. List item

首先,我们把auto_ptr摈弃掉。
因为它比较老,允许多个指针指向同一个变量。
那么回收的时候就会出现一个问题:一个变量被回收了多次。
那肯定是不允许的。

shared_ptr通过技术手段解决了这个析构的问题,unique_ptr则不允许将多个指针指向一个变量,它会在编译的时候直接报错。

  1. List item

相比另外两种模板,unique还有一种支持数组指针的变体。

std::unique_ptr<double[]> dbo(new double[5]);
  1. List item

综上分析可得,shared_ptr支持指针数组,unique_ptr支持数组指针。

  1. List item
    不要将 *this指针交给智能指针。

  2. List item
    不要在函数实参中创建shared_ptr
    function (shared_ptr (new int),g());//有缺陷
    正确的写法应该是先创建智能指针: shared_ptr p(new int()); f(p,g());


什么时候释放智能指针?

这应该也是比较关心的问题吧。

指针的作用域结束时它就自己清理了。至于如果有人非要手动去释放,那我个人建议你用普通指针。

上一篇:TVM性能评估分析(七)


下一篇:c++ shared_ptr 和 左右值 关系记录