百科问答小站 logo
百科问答小站 font logo



unique_ptr 的底层实现是什么样的? 第1页

  

user avatar   qing-bo-72 网友的相关建议: 
      

底层一般是一个compressed_pair,运用c++中的空基类优化。

boost中有实现compressed_pair.hpp

微软stl中的实现compressed_pair

便于理解做简化

       template<typename T1,typename T2, bool = std::is_empty_v<T1>> struct compressed_pair : T1 {    T2  val2; }  template<typename T1,typename T2> struct compressed_pair<T1,T2,false> {    T1 val1;    T2 val2; };      

简单理解就是如果T1类型是空类的化,就继承它,利用空基类优化。否则就是个普通的pair。

这意味着如果你的删除器是无状态的话,unique_ptr尺寸就是一个指针大小。如果携带状态,就会导致尺寸变大。所以并不是定义删除器就会增大尺寸。


user avatar   zhang-yi-40-33-59 网友的相关建议: 
      

std::unique_ptr 需要在类内保存管理的对象指针和删除器对象,在 MSVC 的实现中,底层保存一个 _Compressed_pair,它能在删除器为空时应用空基类优化,以减小对象大小。这就是题主在不提供删除器时(使用默认的删除器 std::default_delete) 大小仅仅包含一个指针的大小的原因。

这里以我手头的 MSVC 的标准库实现为例:

_Compressed_pair 的实现如下:

       template <class _Ty1, class _Ty2, bool = is_empty_v<_Ty1> && !is_final_v<_Ty1>> class _Compressed_pair final : private _Ty1 { // store a pair of values, deriving from empty first public:     _Ty2 _Myval2;     ... };  template <class _Ty1, class _Ty2> class _Compressed_pair<_Ty1, _Ty2, false> final { // store a pair of values, not deriving from first public:     _Ty1 _Myval1;     _Ty2 _Myval2;     ... };      

_Compressed_pair 的第三个模板参数的默认值用于确定该使用主模板还是其特化。通过判断第一个类型 _Ty1 是否为空(is_empty_v<_Ty1>)和是否可以继承(不为 final,即 !is_final_v<_Ty1>),选用两个特化。

其中,若 _Ty1 为空且可继承,则继承自 _Ty1,以实施空基类优化。我想注释中已经说的比较明确了。

为了构造 _Compressed_pair 对象,还定义了两个 tag:

       struct _Zero_then_variadic_args_t {     explicit _Zero_then_variadic_args_t() = default; }; // tag type for value-initializing first, constructing second from remaining args  struct _One_then_variadic_args_t {     explicit _One_then_variadic_args_t() = default; }; // tag type for constructing first from one arg, constructing second from remaining args      

第一个 tag 表示将给定的实参全部用来构造 _Ty2 对象,而 _Ty1 对象被值初始化。因此,使用了该 tag 的构造函数是这样实现的:

       template <class... _Other2> constexpr explicit _Compressed_pair(_Zero_then_variadic_args_t, _Other2&&... _Val2) noexcept(     conjunction_v<is_nothrow_default_constructible<_Ty1>, is_nothrow_constructible<_Ty2, _Other2...>>)     : _Ty1(), _Myval2(_STD forward<_Other2>(_Val2)...) {}      

此处仅仅展示主模板中该构造函数的定义,而特化中也有类似的定义,只不过初始化的对象不同而已。

第二个 tag 表示使用第一个实参构造 _Ty1 对象,使用剩余实参构造 _Ty2 对象,具体应用为:

       template <class _Other1, class... _Other2> constexpr _Compressed_pair(_One_then_variadic_args_t, _Other1&& _Val1, _Other2&&... _Val2) noexcept(     conjunction_v<is_nothrow_constructible<_Ty1, _Other1>, is_nothrow_constructible<_Ty2, _Other2...>>)     : _Ty1(_STD forward<_Other1>(_Val1)), _Myval2(_STD forward<_Other2>(_Val2)...) {}      

std::unique_ptr 就是使用该结构实现的:

       template <class _Ty, class _Dx /* = default_delete<_Ty> */> class unique_ptr { // non-copyable pointer to an object     ... private:     _Compressed_pair<_Dx, pointer> _Mypair; };      

_Ty1 就是删除器类型,_Ty2 就是 pointer 类型,而 pointerunique_ptr 的一个公有类型成员,就是要管理的指针类型。

至于 unique_ptr 不能复制,是因为其复制构造函数和复制赋值运算符都被弃置了:

       unique_ptr(const unique_ptr&) = delete; unique_ptr& operator=(const unique_ptr&) = delete;      

了解清楚 _Compressed_pair 的两个类型的对应关系后,我想其它成员函数也是比较好理解的。unique_ptr 代码也不长,可以试着读一读。




  

相关话题

  c#中虽然异步和多线程是两码事,但是是否异步微软提供的async函数内部还是多线程去实现的? 
  在C++中链表重不重要? 
  C/C++中,int a=15;a储存在哪? 
  倒序输出字符串c++为啥不行? 
  #define 不是简单的替换吗,为什么下面的代码错误? 
  想走虚幻引擎c++路线,c++是否应该大量学习算法? 
  Mac 下顺手的 C/C++ 开发 IDE 是哪个? 
  如何评价网易校招C++的笔试题? 
  如何以最小的改动尽量不改变已有代码的情况下适应不断变更的需求? 
  既然scanf和strcpy等函数会被编译器报不安全,那么C语言教材为什么还讲这些函数? 

前一个讨论
如何看待目前国内「隐私计算」行业现状,市场发展有哪些趋势?
下一个讨论
纳粹德国和法西斯意大利在二战前和战时是怎么互相看待彼此的(官方和民间)?





© 2024-11-25 - tinynew.org. All Rights Reserved.
© 2024-11-25 - tinynew.org. 保留所有权利