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>();
从上述例子我们可以看出以下几点:
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例子 。
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
-
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);
-
}