c++11 make_shared深度研究,从一个函数看仿变长参数模板实现方式

本文详细分析了C++11中的make_shared函数在VS2012中的实现,由于该版本不支持变长参数模板,但make_shared却能处理最多5个参数,揭示了其实现原理。通过宏元编程,生成6个重载函数以实现0到5个参数的make_shared。通过一步步展开宏,逐步展示了从_VARIADIC_EXPAND_0X到各个内部宏的展开过程,解释了make_shared如何利用宏生成代码来实现功能,最后指出虽然实现方式复杂,但这可能是基于已有的宏系统设计的结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

         本文基于vs2012中的std::make_shared函数进行分析,选取原因有两个,一是现在公司再用vs2012版本进行开发,我也就自然根据这个编译器进行的研究,第二是vs2012中并没有支持变长参数模板这个C++11的特性,但是make_shared仍然神奇的支持着“变长参数”,这就说明起码vs2012中的make_shared还没有用到变长参数就实现了这个功能,并且也导致一个问题,就是vs2013版本之后make_shared的实现方式可能发生了改变。所以在开始分析前,我要强调一下我所用的代码版本。

 

         首先我认为还是要介绍一下make_shared这个函数,虽然可能对于大部分人来说这个根本没用,如果觉得没用可以直接跳过这个废话阶段。make_shared是C++11中创建shared_ptr这种智能指针的一种方式,并且实际上很推荐使用这种方式去创建一个智能指针,而不是直接通过原生指针去赋值或者通过shared_ptr的构造函数去创建一个智能指针。因为那样的操作略微存在一些内存泄漏上的风险,具体问题请自行百度shared_ptr。make_shared函数的一般使用方式是auto smart_ptr = std::make_shared<PTR_TYPE>(PARAM_TYPE1param1, PARAM_TYPE2 param2,...);参数就是指针实例化时构造函数需要的参数。而经过试验会发现这个参数数量最大是5,当然理由会在后面说明。

 

         那接下来就正式开始分析这个函数。

         首先通过跳转找到这个函数的定义,会在memory中看到这样一段代码

#define_ALLOCATE_MAKE_SHARED( \

    TEMPLATE_LIST, PADDING_LIST,LIST, COMMA, X1, X2, X3, X4) \

template<class _Ty COMMA LIST(_CLASS_TYPE)> inline \

    shared_ptr<_Ty>make_shared(LIST(_TYPE_REFREF_ARG)) \

    {   /* make a shared_ptr */ \

    _Ref_count_obj<_Ty> *_Rx =\

        new _Ref_count_obj<_Ty>(LIST(_FORWARD_ARG)); \

    shared_ptr<_Ty> _Ret; \

    _Ret._Resetp0(_Rx->_Getptr(),_Rx); \

    return (_Ret); \

    } \

template<class _Ty, \

    class _Alloc COMMA LIST(_CLASS_TYPE)> inline \

    shared_ptr<_Ty>allocate_shared( \

        const _Alloc& _Al_arg COMMA LIST(_TYPE_REFREF_ARG)) \

    {   /* make a shared_ptr */ \

    typedef _Ref_count_obj_alloc<_Ty,_Alloc> _Refoa; \

    typename _Alloc::template rebind<_Refoa>::other _Alref =_Al_arg; \

    _Refoa *_Rx = _Alref.allocate(1);\

    _TRY_BEGIN \

        ::new (_Rx) _Refoa(_Al_arg COMMA LIST(_FORWARD_ARG)); \

    _CATCH_ALL \

        _Alref.deallocate(_Rx, 1); \

    _RERAISE; \

    _CATCH_END \

    shared_ptr<_Ty> _Ret; \

    _Ret._Resetp0(_Rx->_Getptr(),_Rx); \

    return (_Ret); \

    }

 

_VARIADIC_EXPAND_0X(_ALLOCATE_MAKE_SHARED, , , , )

#undef _ALLOCATE_MAKE_SHARED

 

这一段代码中可以找到长得很像make_shared的函数的定义,没错,那东西就是make_shared的定义。但是,这种代码,who understand?整个的函数定义都是包在一个宏里的,而这个宏的运行方式,可以用鬼畜来形容。这个定义实际上并不是c++11里的变长参数的实现方式,而是通过宏元编程,实现的代码生成,然后又通过代码生成,重载了6个make_shared函数。这6个函数分别接受0到5个参数,这也就是之前提到的最多接受5个参数的原因。

 

从结论上来讲,make_shared的定义是通过宏元实现的代码生成而来的重载函数,那么这个定义到底是如何产生的?其实如果熟悉宏的操作的话,会很清楚的了解到这个定义整个是包在一个_ALLOCATE_MAKE_SHARED的宏里的,而这个宏在最后_VARIADIC_EXPAND_0X(_ALLOCATE_MAKE_SHARED

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值