C++11 中推出了三种智能指针,unique_ptr、shared_ptr 和 weak_ptr,同时也将 auto_ptr 置为废弃 (deprecated)。
但是在实际的使用过程中,很多人都会有这样的问题:
- 不知道三种智能指针的具体使用场景
-
无脑只使用 shared_ptr
-
认为应该禁用 raw pointer(裸指针,即 Widget * 这种形式),全部使用智能指针
本文将从这几方面讲解智能指针:
- 智能指针的应用场景分析
- 智能指针的性能分析: 为什么 shared_ptr 性能比 unique_ptr 差
- 指针作为函数参数时应该传,传值、传引用,还是裸指针?
1 对象所有权
首先需要理清楚的概念就是对象所有权的概念。所有权在 rust 语言中非常严格,写 rust 的时候必须要清楚自己创建的每个对象的所有权。
但是 C++ 比较自由,似乎我们不需要明白对象的所有权,写的代码也能正常运行。但是明白了对象所有权,我们才可以正确管理好对象生命周期和内存问题。
C++ 引入了智能指针,也是为了更好的描述对象所有权,简化内存管理,从而大大减少我们 C++ 内存管理方面的犯错机会。
2 std::unique_ptr 专属所有权
我们大多数场景下用到的应该都是 unique_ptr。
unique_ptr 代表的是专属所有权,即由 unique_ptr 管理的内存,只能被一个对象持有。
所以,unique_ptr 不支持复制和赋值,如下:
auto w = std::make_unique<Widget>();
auto w2 = w; // 编译错误
C++
Copy
如果想要把 w 复制给 w2, 是不可以的。因为复制从语义上来说,两个对象将共享同一块内存。
因此,unique_ptr 只支持移动, 即如下:
auto w = std::make_unique<Widget>();
auto w2 = std::move(w); // w2 获得内存所有权,w 此时等于 nullptr
C++
Copy
unique_ptr 代表的是专属所有权,如果想要把一个 unique_ptr 的内存交给另外一个 unique_ptr 对象管理。只能使用 std::move 转移当前对象的所有权。转移之后,当前对象不再持有此内存,新的对象将获得专属所有权。
如上代码中,将 w 对象的所有权转移给 w2 后,w 此时等于 nullptr,而 w2 获得了专属所有权。
2.1 性能
因为 C++ 的 zero cost abstraction 的特点,unique_ptr 在默认情况下和裸指针的大小是一样的。
所以 内存上没有任何的额外消耗,性能是最优的