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函数前,先介绍两个概念(左值和右值) 左值和右值 首先区分左值和右值 左值是表达式结束后依然存在的持久对象(代表一个在内存中占有确定位置的对象) 右值是表达式结束时不 ...
随机推荐
- spring bean中构造函数,afterPropertiesSet和init-method的执行顺序
http://blog.csdn.net/super_ccc/article/details/50728529 1.xml文件 <bean id="aaa" class=&q ...
- Java 线程池使用
在实现类中,运用线程池 serviceImpl.java //定义线程池 private static ThreadPoolExecutor executor1 = new ThreadPoolExe ...
- 简单使用idea Spring Boot搭建项目
第一步:使用Spring Initializr创建 第二步:项目配置 第三步:选择项目需要的依赖 第五步: ok 创建完成,修改仓库 maven{ url 'http://maven.aliyun.c ...
- Spring自定义注解(验证身份证+性别+地区)
第一步:定义注解 PersonFormId: package com.wbg.maven1128.demo_formatter; import java.lang.annotation.*; @Doc ...
- LwIP协议栈开发嵌入式网络的三种方法分析
LwIP协议栈开发嵌入式网络的三种方法分析 摘要 轻量级的TCP/IP协议栈LwIP,提供了三种应用程序设计方法,且很容易被移植到多任务的操作系统中.本文结合μC/OS-II这一实时操作系统,以 ...
- Gradle Goodness: Running Java Applications from External Dependency
With Gradle we can execute Java applications using the JavaExec task or the javaexec() method. If we ...
- 使用canvas输出base64_url
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 史上最简单的SpringCloud教程 | 第十二篇: 断路器监控(Hystrix Dashboard)(Finchley版本)
转载请标明出处: 原文首发于:https://www.fangzhipeng.com/springcloud/2018/08/30/sc-f12-dash/ 本文出自方志朋的博客 在我的第四篇文章断路 ...
- 一点一点看JDK源码(五)java.util.ArrayList 后篇之forEach
一点一点看JDK源码(五)java.util.ArrayList 后篇之forEach liuyuhang原创,未经允许禁止转载 本文举例使用的是JDK8的API 目录:一点一点看JDK源码(〇) 代 ...
- oracle database 9i/10g/11g 编程艺术 源代码下载
背景 在找这本书的源码,搜到提供的都是需要C币下载的.比较固执(其实是穷). 在这本书的前言中提到源代码可以在 www.appress.com 上下载. 下面是该书在该网站上的链接: https:// ...