C++11的右值引用

右值引用 :int &&p

左值引用:即普通引用 int& p

常量左值引用:const int& p

 

共同点:都是变量,都是引用

 

区别:左值引用只能绑左值,右值引用只能绑右值,但注意右值引用同样也是变量,是左值!

常量左值引用却是个奇葩,它可以算是一个“万能”的引用类型,它可以绑定非常量左值、常量左值、右值,而且在绑定右值的时候,常量左值引用还可以像右值引用一样将右值的生命期延长,缺点是,只能读不能改。

如:

1 int f();
2 vector<int> p(100);
3 
4 int &&r1=f();    //f()返回int,是右值
5 int& r2=p[0];    //p的[]重载函数返回int&,是左值
6 int& r3=r1;     //r1虽然是右值引用,但它本身是左值
7 int&& r4=p[0]*f(); //表达式结果是右值

 


 

转载一个知乎的回答:

知乎链接:https://www.zhihu.com/question/64205844/answer/217733257

std::move 并不会真正地移动对象,真正的移动操作是在移动构造函数、移动赋值函数等完成的,std::move 只是将参数转换为右值引用而已(相当于一个 static_cast)。

std::string str = "test";
string&& r = std::move(str);//只是简单的对右值引用r赋值,右值引用=右值引用,不存在移动构造!

中,其实只是定义了一个指向 str 的右值引用而已,str 并没有被移走。这时输出str还是等于“test”。

甚至:

 1 int main()
 2 {
 3     //-------------------------------------------------------------------------
 4     std::string str = "test";
 5     std::string&& r=move(str);//r是一个右值引用
 6     string t(r);//调用拷贝构造函数,因为右值引用在表达式中自动变为左值!
 7     cout<<str;
 8     getchar();
 9     return 0;
10 }

这段代码输出的str依然还是"test"。因为右值引用本身实际是左值,即使r是右值引用,string t(r); 里的r仍然还是左值。所以这里调用的其实是拷贝构造函数,而不是移动构造函数。str 自然也不会被移走。

 

如下代码是可以真正移除str的,要么调用移动构造函数,要么调用移动赋值函数。注意情况2和情况3的区别(声明时拷贝初始化  和  先声明后赋值的区别

 1 int main()
 2 {
 3     //-------------------------------------------------------------------------
 4     std::string str = "test";
 5     //1
 6     string r1(std::move(str));//调用移动构造函数,这里把str的所有权交给了r
 7     //2
 8     string r2=std::move(str);//调用移动构造函数,这里把str的所有权交给了r
 9     //3
10     string r3;
11     r3=std::move(str); //调用移动赋值函数,也可以把str的所有权交给r
12     //--------------------------------------------------------------------------
13     //上面三个任意一种都可以把str真的移走
14     cout<<str;
15     getchar();
16     return 0;
17 }

 

右值引用成员函数和普通(左值)引用成员函数

来历:

之前的c++版本可以这样写:

int main()
{
    string s1 = "abc", s2 = "def";
    auto n = (s1 + s2).find('a');    //对右值调用成员函数
    s1 + s2 = "wc";        //对右值赋值
    cout<<s1<<endl<<s2;
    getchar();
    return 0;
}

输出:

 

string相加产生了一个临时对象,相当于对一个临时对象赋值,是没有意义的,C++ 11之前没有区分左值和右值的语法元素,无法限定assignment operator只能作用于右值。

另一个证据:可以向右值赋值,下面代码不会报错:

 1 class Test
 2 {
 3 private:
 4     int a;
 5 public:
 6     Test(/* args */){}
 7     Test& operator=(const Test& x)     //加&表示只能向左值赋值,加&&表示只能向右值赋值,不加的话都可以匹配,当然优先选择匹配度更高的那个版本
 8     {
 9         a=x.a;
10     }
11     ~Test();
12 };
13 int main()
14 {
15     Test x1,x2;
16     move(x1)=x2;
17     getchar();
18     return 0;
19 }

其中的赋值重载函数更改为:

1 Test& operator=(const Test& x)  &   //加&表示只能向左值赋值,不加的话可以向右值赋值
2     {
3         a=x.a;
4     }

main函数中的move(x1)=x2; 就会报错了,因为Test类不允许向右值赋值。

概括:

引用限定符:&或者&&,对于&修饰的函数,只能用于this是个左值;&&修饰的函数,只能用于this是个右值。

另外:如果该成员函数还是const成员函数,那么const要写在&的前面。如:

Test& operator=(const Test& x) const &
{
    a=x.a;
}

当然上面这个函数只是举例,毕竟赋值运算符重载不可能是const成员函数。

那么右值引用限定的成员函数有什么用呢? 我个人觉得除了兼容以前的C++写法,是没什么卵用的。。。

posted @ 2020-03-06 00:55  NeoZy  阅读(265)  评论(0)    收藏  举报