引言
对于C和C++语言,指针有着独特的作用。通过指针的使用,可以避免很多的拷贝操作,提升性能。但是普通的指针使用不当的话,造成内存泄漏,会导致更加严重的后果。C++为了解决这些问题,提出了引用的技术,然而这依旧不能解决所有的问题,因此c++提出了智能指针技术。
所谓智能指针是指行为类似常规指针,但是它负责自动释放所指向的对象。
新的标准库提供了两种职能指针,分别为shared_ptr和unique_ptr
shared_ptr允许多个指针指向同一个对象
unique_ptr则“独占”所指向的对象
shared_ptr
通过下面的方式可以定义一个空的智能指针
1 | shared_ptr<T> sp; |
我们还可以定义一个指向固定内存的职能指针1
shared_ptr<int> sp(new int(42));
智能指针只能使用直接初始化的方式,而不能使用赋值操作符。如下的操作时非法的
1 | shared_ptr<int> sp = new int(42); // error |
同样的道理,这样返回也是不行的1
2
3shared_ptr<int> clone(int p) {
return new int(p); // error
}
因为智能指针和普通的指针不能混用
而只能用下面的形式1
2
3shared_ptr<int> clone(int p) {
return shared_ptr<int>(new int(p));
}
make_shared
智能指针只能用直接初始化的方式来创建,但是这种形式实际上是不高效的,标准库提供了更加高效的方式,即make_shared1
2
3auto p = make_shared<int>(42);
auto p1 = make_shared<vector<string>>()
auto q(p); // p和q指向同一个对象,此对象有两个引用者
shared_ptr的基本操作
1 | shared_ptr<T> p // 初始化一个空的智能指针,指向T |
unique_ptr
unique_ptr与shared_ptr不同,同一时刻只能有一个unique_ptr指向一个给定对象。
unique_ptr使用如下的方式创建,它没有make_shared函数1
unique_ptr<int> up(new int(42));
unique_ptr不支持拷贝,也不支持赋值,如下的操作都是错误的1
2
3
4unique_ptr<int> up(new int(42)); //correct
unique_ptr<int> up1(up); // error
unique_ptr<int> up2;
up2 = up; // error
unique_ptr支持的操作
1 | unique_ptr<T> u1 // 空的unique_ptr,指向类型为T的对象 |
虽然unique_ptr不能拷贝,但是可以通过release和reset操作将指针的所有权从一个unique_ptr转移给另一个unique_ptr1
2
3unique_ptr<string> p2(p1.release()); // 所有权从p1转移到p2
unique_ptr<string> p3(new string("hello"));
p2.reset(p3.release()); // 所有权从p3转移到p2
案例分析
有一个文本查询程序,输入一个文本,以及一个单词,能够输出这个单词所在文本的行数,同时升序打印这一行的内容。
首先我们要定义数据结构
- 需要一个vector
来存放整个文本的内容 - 需要一个map
>来存放每个单词所在的行数
下面是我们的代码流程
- 定义一个TextQuery类,用来解析文本,同时保存文本的详细信息
- 当查询时,返回查询的结构数据,用类QueryResult来保存
1 | #include "string" |
我们看上面的代码有什么问题?看这里
1 | return QueryResult(name, loc->second, file); |
这一行创建QueryResult,会导致资源的拷贝操作。为了避免资源的拷贝,可以用指针来解决。如果用指针,那么就要对内存进行管理。智能指针现在可以派上用场了
1 | #include "iostream" |