智能指针三个优点:
- 明确资源的所有权
- 避免忘记delete,造成内存泄露
- 对于 exception 情况,执行内存释放(Effective C++ 中的条款)
智能指针类重载了解引用运算符(*)
和成员指向运算符(->)
,同时为了能够在堆中管理各种类型,几乎所有的智能指针都是模板类,包含其功能的泛型实现。
C++11 中的auto_ptr
已经废弃. 现有的 unique_ptr
,shared_ptr
,weak_ptr
和原生指针加起来构成了指针的完整四件套。它们都在头文件<memory>
里面,最常用的是原生指针(没所有权语义的时候),其次是unique_ptr
,后两个除非特定场合需求,能不用就不用。 拷贝shared_ptr
、 eak_ptr
都涉及到atomic
操作,其开销比起拷贝、解引用一个指针都是大很多的。
unique_ptr
unique_ptr
代表的是专属所有权,之所以叫这个名字,是因为它只能指向一个对象,即当它指向其他对象时,之前所指向的对象会被摧毁,不能进行复制操作只能进行移动操作。两个unique_ptr
也不能指向一个对象. 看源码发现,拷贝构造函数和赋值运算符都加了delete:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16template <typename T, typename D = default_delete<T> >
class unique_ptr
{
public:
explicit unique_ptr(pointer p) noexcept;
~unique_ptr() noexcept;
T& operator*() const;
T* operator->() const noexcept;
unique_ptr(const unique_ptr &) = delete;
unique_ptr& operator=(const unique_ptr &) = delete;
unique_ptr(unique_ptr &&) noexcept;
unique_ptr& operator=(unique_ptr &&) noexcept;
// 省略 ...
private:
pointer __ptr;
};
强行使用会报错:
这里需要注意: 既然不能拷贝, 就不能在函数中将unique_ptr作为参数了,因为传参是一个产生副本的过程,用 move(unique_ptr)取代
- unique_ptr内部存储一个原生指针,当
unique_ptr
析构时,它的析构函数将会负责析构它持有的对象,还可以使用自定义的 删除器 - unique_ptr提供了
operator*()
和operator->()
成员函数,像 raw pointer 一样,我们可以使用*
解引用unique_ptr
,使用->
来访问unique_ptr
所持有对象的成员。 unique_ptr
并不提供 copy 操作,但提供了 move 操作,因此可以用std::move()
来转移unique_ptr
, 把一个unique_ptr
的内存交给另外一个unique_ptr
对象管理,。转移之后,当前对象不再持有此内存,新的对象将获得专属所有权- C++14 提供了
std::make_unique<T>()
函数用来直接创建unique_ptr
,但 C++11 没有
unique_ptr
和原生指针的大小是一样的,内存上没有任何的额外消耗,性能是最优的
如果没有为unique_ptr
指定对象,get()返回0
常用方法
1 | class Test |
move
不执行析构,否则新的智能指针无法指向对象了.
reset
reset
有两种用法
如果不加参数,就会销毁对象(执行析构函数),重置智能指针
如果加原生指针做参数,就会先销毁原来指向的对象,然后指向原生指针指向的对象
1
2
3
4
5
6
7
8Test* p3 = new Test();
std::unique_ptr<Test> p4(new Test());
cout<<"p4: "<<p4.get()<<endl;
p4.reset(p3);
cout<< "after reset "<<endl;
cout<< "p4: "<<p4.get()<<endl;
cout<< "p3: "<<p3 <<endl;
运行结果:1
2
3
4
5
6
7
8construct // p3
construct // p4
p4: 0x7adc50
destruct //
after reset
p4: 0x7acc20
p3: 0x7acc20
destruct
需要注意: release不执行析构, reset执行析构
自定义删除器
unique_ptr的定义删除器方式和shared_ptr不同,因为模板的参数不同,前者还需要指定删除器类型.
原型有:
- std::unique_ptr
up(t,d); - std::unique_ptr
up(d); // 空的指针
T为指针管理的对象类型, D为删除器类型, t为管理的对象, d为删除器函数名称
1 | void myclose(Test* t) |
运行结果:1
2
3construct
close func
destructdecltype
用于获取myclose的类型, *
表面它是一个指针类型,即函数指针.
make_unique 不是‘std’的成员 , 原因是make_unique
为C++14才特有的, 如果使用gcc版本小于6.2,编译就会报错,vs2015 msvc 也可以