相关知识:
智能指针是什么?
- 简单来说,智能指针是一个类,它对普通指针进行封装,使智能指针类对象具有普通指针类型一样的操作。
- 具体而言,复制对象时,副本和原对象都指向同一存储区域,如果通过一个副本改变其所指的值,则通过另一对象访问的值也会改变.所不同的是,智能指针能够对内存进行进行自动管理,避免出现悬垂指针等情况。
普通指针存在的问题(悬垂指针):
- C语言、C++语言没有自动内存回收机制,关于内存的操作的安全性依赖于程序员的自觉。
- 程序员每次
new
出来的内存块都需要自己使用delete
进行释放,流程复杂可能会导致忘记释放内存而造成内存泄漏。 - 而智能指针也致力于解决这种问题,使程序员专注于指针的使用而把内存管理交给智能指针。
先来看看普通指针的悬垂指针问题:
当有多个指针指向同一个基础对象时,如果某个指针delete
了该基础对象,对这个指针来说它是明确了它所指的对象被释放掉了,所以它不会再对所指对象进行操作,但是对于剩下的其他指针来说呢?它们还傻傻地指向已经被删除的基础对象并随时准备对它进行操作。于是悬垂指针就形成了,程序崩溃也“指日可待”。
什么是引用计数?
如何来让指针知道还有其他指针的存在呢?
这个时候我们该引入引用计数的概念了。
引用计数是这样一个技巧,它允许有多个相同值的对象共享这个值的实现。
引用计数的使用常有两个目的:
1.简化跟踪堆中(也即C++中new出来的)的对象的过程。
一旦一个对象通过调用new被分配出来,记录谁拥有这个对象是很重要的,因为其所有者要负责对它进行delete。但是对象所有者可以有多个,且所有权能够被传递,这就使得内存跟踪变得困难。引用计数可以跟踪对象所有权,并能够自动销毁对象。可以说引用计数是个简单的垃圾回收体系。
2.节省内存,提高程序运行效率。
如果很多对象有相同的值,为这多个相同的值存储多个副本是很浪费空间的,所以最好做法是让左右对象都共享同一个值的实现。C++标准库中string类采取一种称为”写时复制“的技术,使得只有当字符串被修改的时候才创建各自的拷贝,否则可能(标准库允许使用但没强制要求)采用引用计数技术来管理共享对象的多个对象。
为基础对象类实现智能指针类:(代码中有体现)
引用计数是实现智能指针的一种通用方法。智能指针将一个计数器与类指向的对象相关联,引用计数跟踪共有多少个类对象共享同一指针。
它的具体做法如下:
1.当创建类的新对象时,初始化指针,并将引用计数设置为1;
2.当对象作为另一个对象的副本时,复制构造函数复制副本指针,并增加与指针相应的引用计数(加1);
3.使用赋值操作符对一个对象进行赋值时,处理复杂一点:先使左操作数的指针的引用计数减1(为何减1:因为指针已经指向别的地方),如果减1后引用计数为0,则释放指针所指对象内存。然后增加右操作数所指对象的引用计数(为何增加:因为此时做操作数指向对象即右操作数指向对象)。
4.析构函数:调用析构函数时,析构函数先使引用计数减1,如果减至0则delete对象。
代码涉及内容:
三种方法:
常规指针类(浅复制) 严重缺点:野指针(悬垂指针)
智能指针(计数类) 避免野指针(悬垂指针)
值类型(深复制)
plain_str.h:
1 |
|
smart_ptr.h:
1 |
|
value_ptr.h:
1 |
|
main.cc:
1 |
|