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函数前,先介绍两个概念(左值和右值) 左值和右值 首先区分左值和右值 左值是表达式结束后依然存在的持久对象(代表一个在内存中占有确定位置的对象) 右值是表达式结束时不 ...
随机推荐
- python-装饰器的简单使用
一.介绍 首先我们先来看一个简单的例子,在基础平台中有一个home()和tv()函数,在业务平台中调用此函数时,给出了响应的打印内容: 基础平台: def home(): print('welcome ...
- iOS 帧动画之翻转和旋转动画
记录两个比较简单的动画,一个是翻转的动画,一个是旋转的动画. 旋转动画: 1 [UIView animateWithDuration:3 animations:^{ if (formView) { f ...
- 动态截屏软件jpg格式
软件下载地址:https://github.com/weibanggang/jiedu 开始截屏 保存路径 生成图片 预览
- wordpress上传含中文文件名出现乱码
一.首先到FTP里面找到wp-admin/includes/file.php这个文件. 二.查找wp_handle_upload在文件里面找到以下代码. function wp_handle_uplo ...
- 使用BSRR和BRR寄存器直接操作STM32的I/O端口
STM32的每个GPIO端口都有两个特别的寄存器,GPIOx_BSRR和GPIOx_BRR寄存器,通过这两个寄存器可以直接对对应的GPIOx端口置'1'或置'0'. GPIOx_BSRR的高16位中每 ...
- spring boot从redis取缓存发生java.lang.ClassCastException异常
目录树 异常日志信息 错误原因 解决方法 异常日志信息 2018-09-24 15:26:03.406 ERROR 13704 --- [nio-8888-exec-8] o.a.c.c.C.[.[. ...
- ssm调用后台oracle存储过程统计分析数据
笔者所在项目需要一个统计本机构近6月收入情况(分两种).本机构下级机构收入情况的需求,数据量为百万级. 具体需求是时间.机构都不确定,可为入参. 综合考虑后决定使用后台存储过程统计. 基础表结构如下: ...
- RabbitMQ初学之踩坑记录
1:账号或密码错误 com.rabbitmq.client.AuthenticationFailureException: ACCESS_REFUSED - Login was refused usi ...
- 第一个electron
1 开发环境:node环境 2 下载electron:npm install electron --save-dev 3 package.json配置如下: { "name": & ...
- JQuery制作网页——第八章 使用jQuery操作DOM
1.DOM操作: DOM操作分为三类: ●DOM Core:任何一种支持DOM的编程语言都可以使用它,如getElementById().getElementsByName: ●HTML-DOM:用于 ...