make_shared理解

本章所有内容均从C++ Primer摘录总结

1.为什么使用make_shared?  

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

如下为make_shared的使用:

//p1指向一个值为"9999999999"的string
shared_ptr<string> p1 = make_shared<string>(10, '9');  
shared_ptr<string> p2 = make_shared<string>("hello");   
shared_ptr<string> p3 = make_shared<string>(); 

从上述例子我们可以看出以下几点:

 1)make_shared是一个模板函数;

 2)make_shared模板的使用需要以“显示模板实参”的方式使用,如上题所示make_shared<string>(10, 9),如果不传递显示 模板实参string类型,make_shared无法从(10, '9')两个模板参数中推断出其创建对象类型。

 3)make_shared在传递参数格式是可变的,参数传递为生成类型的构造函数参数,因此在创建shared_ptr<T>对象的过程中调用了类型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<string> p1 = make_shared<string>(10, '9'); 

//扩展如下,对两个参数分别调用std::forward

return shared_ptr<string>(_Sp_make_shared_tag(), _a ,

			  std::forward<int>(10),  

			  std::forward<char>(c));

补充说明:
①模板参数为右值引用,采用引用折叠原理:


 1)参数为左值时,实参类型为普通的左值引用; T& &, T&& &,T& && =>T&

 2)参数为右值时,实参类型为右值: T&& && => T&&

std::forward:是一个模板,通过显示模板实参来调用,调用后forward返回显示实参类型的右值引用。即,forward<T>的返回类型为T&&,在根据上述引用折叠原理即可保存参数是左值还是右值类型;比如:


int i = 0;

std::forward<int>(i), i将以int&传递

std::forward<int>(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<typename _Tp>

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<typename _Tp>

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);

} 

猜你喜欢

转载自blog.csdn.net/Eunice_fan1207/article/details/83052088
今日推荐