forward

 

 

Rvalue Reference 右值引用

当赋值操作的右边是右值(rvalue),左边的对象不需要特意分配内存去存放这个拷贝(copy),而可以搬移(move)右边对象的资源。

用于解决不必要的拷贝和实现完美转发(perfect forwarding)。

 

Move Semantics 移动语义

move 相当于 浅拷贝 + 打断原指针,原来的对象无法再使用。

 

STL 许多地方使用到了右值引用和 move 语义,如 vector 中的 insert() 函数

iterator insert(const_iterator pos, const value_type& x);
iterator insert(const_iterator pos, const value_type&& x)    // 接受右值引用
{ return emplace(pos, std::move(x)); }    // 将左值变量放到std::move()中,就取得了它的右值引用

 

 

 

 

 

#include<iostream>
#include<string>
using namespace std;
template<typename T1, typename T2>
void set(T1 && var1, T2 && var2){
         T1  m_var1 = std::forward<T1>(var1);
         T2 m_var2 = std::forward<T2>(var2);
}


void set2(string && var1, string && var2){
}
void set3(const string & var1, const string & var2){
}
int main()
{
        string str1("hello");
        string str2("world");
        set(str1, str2);
        set("temporary str1","temporary str2");
        set3("temporary str1","temporary str2");
        //set2(str1, str2);
        return 0;
}
 

 

编译没问题

 

 

root@ubuntu:~/c++# vi rvalue3.cpp  +21
#include<iostream>
#include<string>
using namespace std;
template<typename T1, typename T2>
void set(T1 && var1, T2 && var2){
         T1  m_var1 = std::forward<T1>(var1);
         T2 m_var2 = std::forward<T2>(var2);
}


void set2(string && var1, string && var2){
}
void set3(const string & var1, const string & var2){
}
void set4(string & var1, string & var2){
}
int main()
{
        string str1("hello");
        string str2("world");
        set(str1, str2);
        set("temporary str1","temporary str2");
        set3("temporary str1","temporary str2");
        set4("temporary str1","temporary str2");
        //set2(str1, str2);
        return 0;
}

 

 

value3.cpp: In function ‘int main()’:
rvalue3.cpp:24:40: error: invalid initialization of non-const reference of type ‘std::__cxx11::string& {aka std::__cxx11::basic_string<char>&}’ from an rvalue of type ‘std::__cxx11::string {aka std::__cxx11::basic_string<char>}’
  set4("temporary str1","temporary str2");
                                        ^
In file included from /usr/include/c++/5/string:52:0,
                 from /usr/include/c++/5/bits/locale_classes.h:40,
                 from /usr/include/c++/5/bits/ios_base.h:41,
                 from /usr/include/c++/5/ios:42,
                 from /usr/include/c++/5/ostream:38,
                 from /usr/include/c++/5/iostream:39,
                 from rvalue3.cpp:1:
/usr/include/c++/5/bits/basic_string.h:455:7: note:   after user-defined conversion: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
       basic_string(const _CharT* __s, const _Alloc& __a = _Alloc())
       ^
rvalue3.cpp:15:6: note:   initializing argument 1 of ‘void set4(std::__cxx11::string&, std::__cxx11::string&)’
 void set4(string & var1, string & var2){
      ^

 

 

 

 

#include<iostream>
using namespace std;



void process(int& i) {
    cout << "process(int&): " << i << endl;
}

void process(int&& i) {
    cout << "process(int&&): " << i << endl;
}

void forward(int&& i) {
    cout << "forward(int&&): " << i << ", ";
    process(i);
}

int main() {
    int a = 0;
    process(a);         
    process(1);         
    process(move(a));   
    forward(2);         
                        
    forward(move(a));   
    //forward(a);         
    return 0;
}

 

 

 

process(int&): 0
process(int&&): 1
process(int&&): 0
forward(int&&): 2, process(int&): 2
forward(int&&): 0, process(int&): 0
// Rvalue经由forward()传给另一个函数却变为Lvalue,原因是传递过程中它变成了named object

 

#include<iostream>
using namespace std;



void process(int& i) {
    cout << "process(int&): " << i << endl;
}

void process(int&& i) {
    cout << "process(int&&): " << i << endl;
}

void forward(int&& i) {
    cout << "forward(int&&): " << i << ", ";
    process(i);
}

int main() {
    int a=0;
    forward(a);         
    return 0;
}

 

 

 

forward.cpp: In function ‘int main()’:
forward.cpp:21:14: error: no matching function for call to ‘forward(int&)’
     forward(a);         
              ^
forward.cpp:14:6: note: candidate: void forward(int&&) <near match>
 void forward(int&& i) {
      ^
forward.cpp:14:6: note:   conversion of argument 1 would be ill-formed:
forward.cpp:21:14: error: cannot bind ‘int’ lvalue to ‘int&&’
     forward(a);         
              ^
In file included from /usr/include/c++/5/bits/stl_pair.h:59:0,
                 from /usr/include/c++/5/bits/stl_algobase.h:64,
                 from /usr/include/c++/5/bits/char_traits.h:39,
                 from /usr/include/c++/5/ios:40,
                 from /usr/include/c++/5/ostream:38,
                 from /usr/include/c++/5/iostream:39,
                 from forward.cpp:1:
/usr/include/c++/5/bits/move.h:87:5: note: candidate: template<class _Tp> constexpr _Tp&& std::forward(typename std::remove_reference<_From>::type&&)
     forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
     ^
/usr/include/c++/5/bits/move.h:87:5: note:   template argument deduction/substitution failed:
forward.cpp:21:14: note:   couldn't deduce template parameter ‘_Tp’
     forward(a);         
              ^
In file included from /usr/include/c++/5/bits/stl_pair.h:59:0,
                 from /usr/include/c++/5/bits/stl_algobase.h:64,
                 from /usr/include/c++/5/bits/char_traits.h:39,
                 from /usr/include/c++/5/ios:40,
                 from /usr/include/c++/5/ostream:38,
                 from /usr/include/c++/5/iostream:39,
                 from forward.cpp:1:
/usr/include/c++/5/bits/move.h:76:5: note: candidate: template<class _Tp> constexpr _Tp&& std::forward(typename std::remove_reference<_From>::type&)
     forward(typename std::remove_reference<_Tp>::type& __t) noexcept
     ^
/usr/include/c++/5/bits/move.h:76:5: note:   template argument deduction/substitution failed:
forward.cpp:21:14: note:   couldn't deduce template parameter ‘_Tp’
     forward(a);         
              ^

 

 

 使用 std::forward<T>(),保留参数的左/右值特性。

 

#include<iostream>
using namespace std;



void process(int& i) {
    cout << "process(int&): " << i << endl;
}

void process(int&& i) {
    cout << "process(int&&): " << i << endl;
}

void forward(int&& i) {
    cout << "forward(int&&): " << i << ", ";
    process(std::forward<int>(i));
}

int main() {
    int a=0;
    forward(move(a));
    forward(2);      
    return 0;
}

 

root@ubuntu:~/c++# g++ -std=c++11  forward.cpp  -o  forward
root@ubuntu:~/c++# ./forward
forward(int&&): 0, process(int&&): 0
forward(int&&): 2, process(int&&): 2

 

posted on 2021-04-21 12:08  tycoon3  阅读(684)  评论(0编辑  收藏  举报

导航