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  模版重载

因为存在模版重载机制,所以左值使用第一个版本,而右值选择第二个版本。

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*)0, __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, 1);
          }
          _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, 1);
      __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, 1);
          __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例子,还应用了可变参数模版和转发参数包语法,需要进一步了解。本人水平有限,如果错误请指正谢谢。

时间: 2024-10-14 07:32:00

C++0x,std::move和std::forward解析的相关文章

C++11学习笔记:std::move和std::forward源码分析

std::move和std::forward是C++0x中新增的标准库函数,分别用于实现移动语义和完美转发. 下面让我们分析一下这两个函数在gcc4.6中的具体实现. 预备知识 引用折叠规则: X& + & => X& X&& + & => X& X& + && => X& X&& + && => X&& 函数模板参数推导规则(右值引用参数部分):

std::move()和std::forward()

std::move(t)负责将t的类型转换为右值引用,这种功能很有用,可以用在swap中,也可以用来解决完美转发. std::move()的源码如下 template<class _Ty> inline _CONST_FUN typename remove_reference<_Ty>::type&& move(_Ty&& _Arg) _NOEXCEPT { // forward _Arg as movable return (static_cast

C++ 11 左值,右值,左值引用,右值引用,std::move, std::foward

这篇文章要介绍的内容和标题一致,关于C++ 11中的这几个特性网上介绍的文章很多,看了一些之后想把几个比较关键的点总结记录一下,文章比较长.给出了很多代码示例,都是编译运行测试过的,希望能用这些帮助理解C++ 11中这些比较重要的特性. 关于左值和右值的定义 左值和右值在C中就存在,不过存在感不高,在C++尤其是C++11中这两个概念比较重要,左值就是有名字的变量(对象),可以被赋值,可以在多条语句中使用,而右值呢,就是临时变量(对象),没有名字,只能在一条语句中出现,不能被赋值. 在 C++1

Reference Collapsing Rules, Universal Reference and the implementation of std::forward() and std::move()

关于reference collapsing,可以看这个链接.(里面也讲了std::forward()和std::move()的实现) http://thbecker.net/articles/rvalue_references/section_08.html 需要注意的是,在做auto-type deduction和template-type deduction的时候,在会有reference-stripping 发生:(来自scott meyers) Note that when doing

c++11 标准库函数 std::move 和 完美转发 std::forward

c++11 标准库函数 std::move 和 完美转发 std::forward #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <vector> #include <map> // C++中还有一个被广泛认同的说法,那就是可以取地址的.有名字的就是左值,反之,不能取地址的.没有名字的就是右值. // 相对于左值,右值表示字面常量.表达式.函数的非

C++ 移动语义--std::move 实例解析

移动语义--std::move 编译器只对右值引用才能调用转移构造函数和转移赋值函数,而所有命名对象都只能是左值引用,如果已知一个命名对象不再被使用而想对它调用转移构造函数和转移赋值函数,也就是把一个左值引用当做右值引用来使用,怎么做呢?标准库提供了函数 std::move,这个函数以非常简单的方式将左值引用转换为右值引用. 对于右值引用而言,它本身是右值么? 要看情况. a. 字符串的定义 b. ArrayWrapper String.cc 1 #include<iostream> 2 #i

[转载]如何在C++03中模拟C++11的右值引用std::move特性

本文摘自: http://adamcavendish.is-programmer.com/posts/38190.htm 引言 众所周知,C++11 的新特性中有一个非常重要的特性,那就是 rvalue reference,右值引用. 引入它的一个非常重要的原因是因为在 C++ 中,常常右值,通俗地讲"在等号右边的"临时变量或者临时对象,我们是无法得到它的修改权限的. 由于类的构造和析构机制,往往产生的临时变量或临时对象的拷贝构造及析构,会带来不少的时间.资源消耗. 也同样由于这样的限

c++11之右值引用和std::move

这两个特性是c++11里比较有性能提升意义的.个人认为这两个特性也体现了c++对性能提升的极限追求. 通过改写经典c++面试题mystring来体会 move不能减少临时变量的产生,但是可以减少内存的维护量 代码 //右值引用 /* 左值对象:持久存在的对象,具有名字,可以对其去地址 右值对象:临时对象,表达式结束后它就没了,不能对它取地址,它也没有名字~ 右值引用类型:引用右值的类型,用&&来表示 */ /*****************************************

C++ Primer 笔记——理解std::move

标准库move函数是使用右值引用的模板的一个很好的例子.标准库是这样定义std::move的: template <typename T> typename remove_reference<T>::type&& move(T&& t) { return static_cast<typename remove_reference<T>::type&&>(t); } 我们考虑如下代码的工作过程: std::str