C++0x,std::move和std::forward解析
1.std::move
1.1std::move是如何定义的
template<typename _Tp>
constexpr typename std::remove_reference<_Tp>::type&&
move(_Tp&& __t) noexcept
{ return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
1.2 std::move是如何工作的
1.2.1传入一个右值
a.如果传入是一个右值string,比如“hello”,推断出_Tp类型为string
b.std::remove_reference<_Tp>::type的类型依旧为string
c.move函数的返回类型为string&&
d.move函数的参数类型为string&&
e.static_cast显式转换类型为string&&
1.2.2传入一个左值
a.推断出_Tp的类型为string&
b.std::remove_reference<_Tp>::type的类型为string
c.move函数的返回类型为string&&
d.move函数的参数类型为string& &&,会折叠为string&
e.static_cast显式转换类型为string&&
1.3引用折叠
a.X& &,X& &&和X&& &都折叠为X&
b.X&& && 折叠为X&&
2.std::forward
2.1std::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);
}
2.2std::forward是如何工作的
2.2.1_Tp类型是左值引用
a.如果中转函数的实参是左值string,_Tp的类型为string&,std::remove_reference<_Tp>::type为string
b.forward函数参数__t的类型折叠后为string&
c.string& && (_Tp&&)折叠后依旧为左值引用string&
d.forword函数的返回为string&
2.2.2_Tp类型是右值
a.如果中转实参是右值sting,_Tp的类型为sting,std::remove_reference<_Tp>::type为string
b.forward函数参数__t的类型为string&&
c.forword函数的返回为string&&
2.3 模版重载
此处存在错误!因为存在模版重载机制,所以左值使用第一个版本,而右值选择第二个版本。
更正:完美转发时 ,只有左值,因为右值引用一旦有名字,就是左值!!!必定选择第一个版本,在非完美转发场景下存在如下规则
A a;
std::forward<A&>(std::move(a)); //版本 2 error
A&& a = std::forward<A&&>(A()); //版本 2 ok
A&& b = std::forward<A>(A()); // 版本 2 ok
上述代码抛出异常。
3.STL转发的例子
// shared_ptr.h
// This constructor is non-standard, it is used by allocate_shared.
template<typename _Alloc, typename... _Args>
shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
_Args&&... __args)
: __shared_ptr<_Tp>(__tag, __a, 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)...);
} 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)...);
}
//shared_ptr_base.h
#ifdef __GXX_RTTI
protected:
// This constructor is non-standard, it is used by allocate_shared.
template<typename _Alloc, typename... _Args>
__shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
_Args&&... __args)
: _M_ptr(), _M_refcount(__tag, (_Tp*), __a,
std::forward<_Args>(__args)...)
{
// _M_ptr needs to point to the newly constructed object.
// This relies on _Sp_counted_ptr_inplace::_M_get_deleter.
void* __p = _M_refcount._M_get_deleter(typeid(__tag));
_M_ptr = static_cast<_Tp*>(__p);
__enable_shared_from_this_helper(_M_refcount, _M_ptr, _M_ptr);
}
#else
template<typename _Alloc>
struct _Deleter
{
void operator()(_Tp* __ptr)
{
typedef allocator_traits<_Alloc> _Alloc_traits;
_Alloc_traits::destroy(_M_alloc, __ptr);
_Alloc_traits::deallocate(_M_alloc, __ptr, );
}
_Alloc _M_alloc;
}; template<typename _Alloc, typename... _Args>
__shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
_Args&&... __args)
: _M_ptr(), _M_refcount()
{
typedef typename _Alloc::template rebind<_Tp>::other _Alloc2;
_Deleter<_Alloc2> __del = { _Alloc2(__a) };
typedef allocator_traits<_Alloc2> __traits;
_M_ptr = __traits::allocate(__del._M_alloc, );
__try
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2070. allocate_shared should use allocator_traits<A>::construct
__traits::construct(__del._M_alloc, _M_ptr,
std::forward<_Args>(__args)...);
}
__catch(...)
{
__traits::deallocate(__del._M_alloc, _M_ptr, );
__throw_exception_again;
}
__shared_count<_Lp> __count(_M_ptr, __del, __del._M_alloc);
_M_refcount._M_swap(__count);
__enable_shared_from_this_helper(_M_refcount, _M_ptr, _M_ptr);
}
#endif
//new_allocator.h
#if __cplusplus >= 201103L
template<typename _Up, typename... _Args>
void
construct(_Up* __p, _Args&&... __args)
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
上面STL例子,还应用了可变参数模版和转发参数包语法,需要进一步了解。本人水平有限,如果错误请指正谢谢。
C++0x,std::move和std::forward解析的更多相关文章
- C++11 std::move和std::forward
下文先从C++11引入的几个规则,如引用折叠.右值引用的特殊类型推断规则.static_cast的扩展功能说起,然后通过例子解析std::move和std::forward的推导解析过程,说明std: ...
- item 23: 理解std::move和std::forward
本文翻译自<effective modern C++>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 根据std::move和std::forward不 ...
- C++11中std::move、std::forward、左右值引用、移动构造函数的测试
关于C++11新特性之std::move.std::forward.左右值引用网上资料已经很多了,我主要针对测试性能做一个测试,梳理一下这些逻辑,首先,左值比较熟悉,右值就是临时变量,意味着使用一次就 ...
- std::move()和std::forward()
std::move(t)负责将t的类型转换为右值引用,这种功能很有用,可以用在swap中,也可以用来解决完美转发. std::move()的源码如下 template<class _Ty> ...
- 关于C++11中的std::move和std::forward
std::move是一个用于提示优化的函数,过去的c++98中,由于无法将作为右值的临时变量从左值当中区别出来,所以程序运行时有大量临时变量白白的创建后又立刻销毁,其中又尤其是返回字符串std::st ...
- [C/C++]关于C++11中的std::move和std::forward
http://www.cnblogs.com/cbscan/archive/2012/01/10/2318482.html http://blog.csdn.net/fcryuuhou/article ...
- 透彻理解C++11新特性:右值引用、std::move、std::forward
目录 浅拷贝.深拷贝 左值.右值 右值引用类型 强转右值 std::move 重新审视右值引用 右值引用类型和右值的关系 函数参数传递 函数返还值传递 万能引用 引用折叠 完美转发 std::forw ...
- Item 25: 对右值引用使用std::move,对universal引用则使用std::forward
本文翻译自<effective modern C++>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 右值引用只能绑定那些有资格被move的对象上去.如 ...
- 一文带你详细介绍c++中的std::move函数
前言 在探讨c++11中的Move函数前,先介绍两个概念(左值和右值) 左值和右值 首先区分左值和右值 左值是表达式结束后依然存在的持久对象(代表一个在内存中占有确定位置的对象) 右值是表达式结束时不 ...
随机推荐
- IP黑白名单
防攻击可以增加IP白名单/etc/hosts.allow和黑名单/etc/hosts.deny /etc/hosts.allow IP白名单 /etc/hosts.deny IP黑名单 /etc ...
- AWS backup
shadowsocks ssserver -c /etc/shadowsocks/config.json start/stop/reset
- Unity透明视频播放 所需的Shader脚本
Shader "Custom/ShaderMovie" { Properties { _MainTex("Color (RGB)", 2D) = "b ...
- react系列(四)Redux基本概念和使用
Redux基本概念和使用 先从Flux开始 先放一个Flux官网的链接.需要fq. Flux是Facebook提出的一种构建客户端网页应用的应用架构,它是一种抽象程度很高的设计模式,鼓励单向数据流. ...
- angular1的复选框指令--checklistModel
这个指令可以改变一组checkbox的model格式,提交的时候格式为[x,y,z,...] //复选框指令 .directive('checklistModel', ['$parse', '$com ...
- iOS视频处理
在iOS中,apple提供了AVFoundation 用来处理音视频,基本能满足一些常用的音视频处理需求,而且能调用的硬件编解码接口,能提高不少效率,这是其它库所不能达到的.最近做过的Recnow S ...
- python类的反射使用方法
曾经,博主的房东养了只金毛叫奶茶,今天就拿它当议题好了. 博主写本文时正在被广州的蚊子围攻. #反射练习 class animal(object): def __init__(self,name,fo ...
- vue项目出现空格警告的原因及其解决办法
原因: 因为你的Webpack 配置中大概是使用了 eslint-loader,这是用来规范代码风格的,在多人协作或大项目中推荐使用,不想要则可以在 webpack.config.js 中去掉.esl ...
- centos6,python3,通过pip安装pycurl出现报错提示
Centos6.7系统,python3.6.7,通过 pip 安装pycurl出现报错: __main__.ConfigurationError: Could not run curl-config: ...
- 02JavaScript用法
前言: 介绍一下javascript的最基础语法规范和用法. HTML 中的脚本必须位于 <script> 与 </script> 标签之间. 脚本可被放置在 HTML 页面的 ...