右值参考和左值参考有什么区别?

时间:2017-08-23 09:14:58

标签: c++ reference

在阅读了一些有关右值参考的材料后,我有更多问题然后答案。从这里我读到了rvalue ref:

这里我举了一个简单的例子来帮助我理解:

#include <iostream>

using namespace std;

class A
{
public:
A() :m_a(0), m_pa(nullptr) { cout << "constructor call" << endl; };
~A() { cout << "destructor call" << endl; };

A(A& other) :m_a(0), m_pa(nullptr)
{
    cout << "copy constructor" << endl;
}

A(A&& other) :m_a(0), m_pa(nullptr)
{
    cout << "move constructor" << endl;
}

A& operator=(A&& other)
{
    this->m_a = other.m_a;
    this->m_pa = other.m_pa;
    other.m_a = 0;
    other.m_pa = nullptr;
    return *this;
}

A& operator=(A& other)
{
    this->m_a = other.m_a;
    this->m_pa = other.m_pa;
    other.m_a = 0;
    other.m_pa = nullptr;
    return *this;
}

private:
int m_a;
int* m_pa;
};

int main()
{
A(test2);//constructor
A test4(test2);//copy constructor
//? - move constructor
return 0;
}

我不明白&amp;&amp;的特别之处。在上面的例子中,我可以用&amp;。

做这样的事情
A& operator=(A& other)
{
    this->m_a = other.m_a;  //copy value
    this->m_pa = other.m_pa;//copy pointer address
    other.m_a = 0;          
    other.m_pa = nullptr;//clean "other" object properties from preventing destructor to delete them and lose pointer address
    return *this;
}

问题:

  • 如果我可以用&amp;如果不使用额外的内存分配和复制操作,我为什么要使用&amp;&amp;?
  • 如何获取没有标识符并保存的值?

示例2:

#include <iostream>

using namespace std;

void printReference (int& value)
{
    cout << "lvalue: value = " << value << endl;
}

void printReference (int&& value)
{
    cout << "rvalue: value = " << value << endl;
}

int getValue ()
{
int temp_ii = 99;
return temp_ii;
}

int main()
{ 
  int ii = 11;
  printReference(ii);
  printReference(getValue());  //  printReference(99);
  return 0;
}

问题:

  • 为什么要使用&amp;&amp;在这种情况下,这对我有什么帮助?为什么不直接存储getValue的返回值并将其打印出来?

3 个答案:

答案 0 :(得分:1)

在您阅读了一些关于右值的内容之后,这里有一些关于右值的more材料 我认为你可能缺少的一点,不是(仅)你可以做什么,而是应该做什么。

您的第一个示例有几个问题:

您无法将const值复制到A的实例。

const A a1;
A a2(a1);   // won't compile
A a3;
a3 = a1;    // won't compile
  

我不明白&amp;&amp;的特别之处。在上面的例子中,我可以用&amp;。

做这样的事情

是的,你可以做你的建议。但它是纯粹设计的副本分配。考虑一下:
我写了一个共享库,我的副本ctor就像你在你的建议中所做的那样。您无权访问我的代码,只能访问标题。在我的副本ctor和assigment运算符中,我获取了传递给我的库的实例的所有权。没有描述作业正在做什么......你是否明白了这一点,我不能取得你的实例的所有权!例如:

// my header:
// copy ctor
A& operator=(A& other); 

// your code:
A a1;
A a2(a1);   // from now on, a1 is broken and you don't know it!!!
cout << a1; // pseudo code: prints garbage, UD, crash!!!

您始终应该定义copy-ctors / assignments参数 const

A(A const& other);
A& operator=(A const& other);
// ...
const A a1;
A a2(a1);           // will compile
A a3;
a3 = a1;            // will compile + due to the fact a1 is passed const a3 cannot mutate a1 (does not take ownership)
cout << a1;         // pseudo code: everything is fine
a3 = std::move(a1); // a3 takes ownership from a1 but you stated this explicitly as you want it

Here是一个可以玩的小例子。请注意,复制构造函数是const,但复制赋值不是。然后你可以看到他们的不同之处。

答案 1 :(得分:0)

  

如果我可以用&amp;不使用额外的内存分配和复制操作我为什么要使用&amp;&amp;?

你写的&左值引用的赋值运算符非常非常糟糕。你不希望发表像

这样的陈述
a = b;

损坏 b,但那是你的建议。通常的赋值运算符精确地使用const& ,因为它不应该改变表达式的右侧。

因此,当你想要窃取右手边的状态时,你应该使用rvalue-reference赋值运算符(移动赋值),例如当它出现时。是一个匿名的临时或你明确move它:

a = return_anonymous_temporary(); // ok: the rhs value would expire anyway
a = std::move(b);                 // ok: the damage to b is explicit now

但这种行为不应该是默认行为。

答案 2 :(得分:0)

  

如果我可以用&amp;不使用额外的内存分配和复制操作我为什么要使用&amp;&amp;?

因为它允许你为rvalues和lvalues重载一个函数,并且每个函数都有不同的行为。您在两个重载中都有相同的行为,因此在这种情况下您不需要右值引用。

更一般地说,rvalue引用参数允许您传递临时值,同时允许从该参数移动。

  

为什么要使用&amp;&amp;在这种情况下,这对我有什么帮助?

当参数为右值时,它允许您打印"rvalue"

  

为什么不直接存储getValue的返回值并将其打印出来?

然后,您无法为左值打印"rvalue",为左值打印"lvalue"

除了移动构造函数/赋值运算符之外,r值非常有用的情况并不多。