0.简介
unique_ptr是C++11引入的一种独占所有权的智能指针,其提供了自动管理内存的能力,同时保持有和裸指针相近的性能开销。本文将原理,源码和使用来进行介绍。
1.背景介绍(从问题来看其必要性)
在开发C++代码过程中,通过手动管理内存,常常存在以下问题:
1)内存泄漏(忘记delete)和悬垂指针(被提前delete):这也是所有智能指针要解决的核心问题。
2)所有权不明确:谁负责释放的问题,这个不同的智能指针有着自己的计算方式,shared_ptr通过引用计数,在哪引用计数减为0就在哪释放;而unique_ptr通过独占所有权,谁最后占用谁出作用域释放。
2.原理
unique_ptr的设计其实比较简单,像模板等在shared_ptr文章中有相应介绍,不再赘述,只看其核心的设计思想。
1)独占所有权:同一时间只能有一个unique_ptr指向某个对象,其被销毁时,其管理的对象也一并销毁。
2)转移而不拷贝:所有权通过移动语义转移,不能通过拷贝赋值。
3)轻量级设计:操作接近原始指针。
4)可定制删除器:和shared_ptr一样,unique_ptr也可以定制删除器。
3.源码解读
源码解读部分我们还是先看其成员变量,其成员变量就只有一个,也就是__uniq_ptr_impl,其内部成员如下,通过一个tuple来存储原始指针和自定义删除器:
tuple<pointer, _Dp> _M_t;
看完成员变量后,我们来看其成员函数定义,首先看如何实现不允许拷贝,只允许移动,其通过delete拷贝构造函数来实现。
// Disable copy from lvalue.
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
接下来来看一下make_unique的实现,其通过完美转发将参数转给new运算符,构造出原始指针,然后传给构造函数就可以。
/// std::make_unique for single objects
template<typename _Tp, typename... _Args>
inline typename _MakeUniq<_Tp>::__single_object
make_unique(_Args&&... __args)
{ return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
/// std::make_unique for arrays of unknown bound
template<typename _Tp>
inline typename _MakeUniq<_Tp>::__array
make_unique(size_t __num)
{ return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]()); }
/// Disable std::make_unique for arrays of known bound
template<typename _Tp, typename... _Args>
inline typename _MakeUniq<_Tp>::__invalid_type
make_unique(_Args&&...) = delete;
再来看一下析构,其根据设置的释放器来进行释放:
/// Destructor, invokes the deleter if the stored pointer is not null.
~unique_ptr() noexcept
{
static_assert(__is_invocable<deleter_type&, pointer>::value,
"unique_ptr's deleter must be invocable with a pointer");
auto& __ptr = _M_t._M_ptr();
if (__ptr != nullptr)
get_deleter()(std::move(__ptr));
__ptr = pointer();
}
4.使用方式
其基本使用方式可以参考如下:
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() { std::cout << "MyClass created" << std::endl; }
~MyClass() { std::cout << "MyClass destroyed" << std::endl; }
void doSomething() { std::cout << "Doing something..." << std::endl; }
};
int main() {
// 创建方式一:使用make_unique(C++14及以后)
auto ptr1 = std::make_unique<MyClass>();
ptr1->doSomething();
// 创建方式二:使用构造函数(C++11)
std::unique_ptr<MyClass> ptr2(new MyClass());
// 错误:不能拷贝unique_ptr
// std::unique_ptr<MyClass> ptr3 = ptr1; // 编译错误
// 正确:可以移动unique_ptr
std::unique_ptr<MyClass> ptr3 = std::move(ptr1);
if (ptr1 == nullptr) {
std::cout << "ptr1 is now null" << std::endl;
}
// 通过reset()释放所有权
ptr2.reset(); // 显式释放资源
// 通过release()转移所有权
MyClass* rawPtr = ptr3.release(); // ptr3变为空
delete rawPtr; // 需要手动释放
return 0;
}