为什么要讲讲智能指针, 因为发现很多人根本说不出什么是智能指针, 一说到智能指针就会提引用计数。引用计数不是智能指针, 引用计数只是智能指针的一种实现方式。
(1) 何为智能指针?
说到智能指针, 我们首先应该说一下普通指针的优缺点。
优点: 灵活, 可以直接获取内存所指向数据。
缺点: 必须手动管理所指向内存, 容易出bug, 维护困难。
智能指针应该保持普通指针优点, 剔出其缺点。
于是智能指针可以定义为: 具有指针性质, 但是能够自动释放内存(资源)的结构体(类)。
(2) 如何保持指针的性质?
指针的两大操作是:
1) 取值: *p。
2) 指向成员: p->member。
因此智能指针必须要重载operator* 和 operator->。
(3) 如何自动释放内存?
自然是在析构函数中销毁。
有了以上的思路, 现在我们可以尝试着写代码了,我们以int型指针为例,最后我们可以用模板实现。
(1)这样就会出现两个问题,a)如何判断是否为空指针,b) copy构造函数和赋值运算符如何写?
我们可以增加一个get函数来获取裸指针,或者重载bool转换运算符。
(2)copy构造函数和赋值运算符一般有以下几种思路
1)让 拷贝构造函数和赋值运算符不可用。
2)深copy rawPtr_。
3)浅copy rawPtr_。
1) Disable copy构造和赋值运算符是有实用价值, 因为很多场景是拥有关系, 比如一个类A拥有一个指针p, 那我们可以修改为这个类A拥有一个p的智能指针,由于智能指针的自动析构,就免去了在类A的析构函数中显式删除p。
(3)2) 深copy指针和类的一般实现原则其实并无差异,这样就使新建了一个SmartIntPtr,那么可以用SmartIntPtr sp2(new int(*sp1))替换, 也可以新建了sp2后重新赋值即:*sp2 = *sp1。
(4)深copy必须要考虑被copy的指针是否为空。
3)浅copy指针,这个实现起来很方便。
但是这里面有个问题, 内存怎么删除, 所有的copy都拥有这个指针,都会在析构函数中删除内存,势必产生问题。
我们在回到一个原始的问题? 一个指针怎么去使用,一般有两种方法:
1)指针指关联到一个对象, 并且指针在对象创建时被创建。
2)指针只在一个对象关联,对象负责删除,但是指针是从对象外界传递进对象的。
3)指针被很多对象关联, 但是只有一个地方删除它,关联它的地方都可以修改它的内容。
第1)与2)类型,我们在上面的SmartIntPtrDisableCopy和SmartIntPtrDeepCopy里面已经基本实现了。3)如何处理,SmartIntPtrShallowCopy的思想, 但是如何解决指针多重删除问题?还有问题是智能指针的传递,如果Disable copy, 那么就无法值传递, 如果是Deep copy那么每次都要重新建立申请一份内存,用完之后就自动delete,效率上不高。而且被传递的指针不是原来的指针了。
我们将在下面章节中,对以上两个问题(1)指针的传递和(2)共享指针的构析的解决方法。
网友评论