make_shared

本文深入探讨了C++中make_shared函数的作用与实现,解释了如何利用make_shared安全地管理动态内存,并通过实例展示了其与shared_ptr的结合使用。文章详细分析了make_shared的模板实现,包括可变参数模板、右值引用与std::forward机制,以及如何通过完美转发保持实参类型。

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

1.为什么使用make_shared?
make_shared函数的主要功能是在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr;由于是通过shared_ptr管理内存,因此一种安全分配和使用动态内存的方法。

 如下为make_shared的使用:

//p1指向一个值为"9999999999"的string
shared_ptr p1 = make_shared(10, ‘9’);

shared_ptr p2 = make_shared(“hello”);

shared_ptr p3 = make_shared();
从上述例子我们可以看出以下几点:
1)make_shared是一个模板函数;
2)make_shared模板的使用需要以“显示模板实参”的方式使用,如上题所示make_shared(10, 9),如果不传递显示 模板实参string类型,make_shared无法从(10, ‘9’)两个模板参数中推断出其创建对象类型。
3)make_shared在传递参数格式是可变的,参数传递为生成类型的构造函数参数,因此在创建shared_ptr对象的过程中调用了类型T的某一个构造函数。
2.make_shared模板实现
如下为make_shared的库函数实现版本:

template<typename _Tp, typename… _Args>
inline shared_ptr<_Tp>
make_shared(_Args&&… __args)
{
typedef typename std::remove_const<_Tp>::type _Tp_nc;
return std::allocate_shared<_Tp>(std::allocator<_Tp_nc>(),
std::forward<_Args>(__args)…);
}

template<typename _Tp, typename _Alloc, typename… _Args>
inline shared_ptr<_Tp>
allocate_shared(const _Alloc& __a, _Args&&… __args)
{
return shared_ptr<_Tp>(_Sp_make_shared_tag(), __a,
std::forward<_Args>(__args)…);
}
我们依次分析上述的关键代码
//关键行1
template<typename _Tp, typename… _Args>
inline shared_ptr<_Tp> make_shared(_Args&&… __args)

//关键行2
std::forward<_Args>(__args)…

//关键行3
return shared_ptr<_Tp>(_Sp_make_shared_tag(), __a,
std::forward<_Args>(__args)…);
从上述关键代码可以看出:make_shared是组合使用可变参数模板与forward(转发)机制实现将实参保持不变地传递给其他函数。如最开始的string例子。
1)使用可变参数:是因为string有多个构造函数,且参数各不相同;
2)Args参数为右值引用(Args&&)和std::forward:是为了保持实参中类型信息的传递。这样当传递一个右值string&& 对象给make_shared时,就可以使用string的移动构造函数进行初始化。注意,两者必须结合使 用,缺一不可;

此外std::forward<_Args>(__args)…是采用包扩展形式调用的,原理如下:
shared_ptr p1 = make_shared(10, ‘9’);

//扩展如下,对两个参数分别调用std::forward
return shared_ptr(_Sp_make_shared_tag(), _a ,
std::forward(10),
std::forward©);
补充说明:
①模板参数为右值引用,采用引用折叠原理:
1)参数为左值时,实参类型为普通的左值引用; T& &, T&& &,T& && =>T&
2)参数为右值时,实参类型为右值: T&& && => T&&
②std::forward:是一个模板,通过显示模板实参来调用,调用后forward返回显示实参类型的右值引用。即,forward的返回类型为T&&,在根据上述引用折叠原理即可保存参数是左值还是右值类型;比如:
int i = 0;
std::forward(i), i将以int&传递
std::forward(42), 42将以int&&传递
std::forward实现代码:
/**

  • @brief Forward an lvalue.
  • @return The parameter cast to the specified type.
  • This function is used to implement “perfect forwarding”.
    */
    template
    constexpr _Tp&&
    forward(typename std::remove_reference<_Tp>::type& __t) noexcept
    { return static_cast<_Tp&&>(__t); }

/**

  • @brief Forward an rvalue.
  • @return The parameter cast to the specified type.
  • This function is used to implement “perfect forwarding”.
    */
    template
    constexpr _Tp&&
    forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
    {
    static_assert(!std::is_lvalue_reference<_Tp>::value, “template argument”
    " substituting _Tp is an lvalue reference type");
    return static_cast<_Tp&&>(__t);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值