右值引用和左值引用有什么区别?
What is the difference between rvalue reference and lvalue reference?
在阅读了一些关于右值参考的材料后,我有更多的问题而不是答案。从这里我读到了关于右值参考:
- 文档右值参考 (1(
- 文档右值参考 (2(
- 文档右值参考 (3 - 书(
在这里,我做了一个简单的例子来帮助我理解:
#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;
}
我不明白 && 有什么特别之处。在上面的例子中,我可以用 &
.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;
}
问题:
- 如果我可以在不使用额外内存分配和复制操作的情况下执行此操作,为什么我应该使用 &&?
- 如何获取没有标识符的值并保存?
示例 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;
}
问题:
- 为什么在这种情况下使用 &&&,这对我有什么帮助?为什么不直接存储getValue的返回并打印出来呢?
在你读了一些关于右值的东西之后,这里有一些关于右值的更多材料。
我认为你可能错过的一点不是(不仅(你能做什么,而是你应该做什么。
您的第一个示例存在多个问题:
您无法将 const 值复制到A
的实例。
const A a1;
A a2(a1); // won't compile
A a3;
a3 = a1; // won't compile
我不明白 && 有什么特别之处。在上面的例子中,我可以用 &
.
是的,你可以按照你的建议去做。但它纯粹是设计的副本同名。考虑一下:
我写了一个共享库,我的复制 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!!!
您始终应定义复制 ctors/赋值参数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
这里有一个小例子,你可以玩。请注意,复制构造函数是 const,但复制赋值不是。然后你可以看到它们的不同之处。
如果我可以在不使用额外内存分配和复制操作的情况下执行此操作,为什么我应该使用 &&?
你写的赋值运算符&
左值引用是非常非常糟糕的。你不会期望这样的陈述
a = b;
损坏b
,但这就是你的建议。通常的赋值运算符之所以采用const&
,正是因为它不应该改变表达式的右侧。
因此,当您确实想要窃取右侧的状态时,例如当它是匿名临时状态或您显式move
它时,您应该使用 rvalue-reference 赋值运算符(移动赋值(:
a = return_anonymous_temporary(); // ok: the rhs value would expire anyway
a = std::move(b); // ok: the damage to b is explicit now
但是,这种行为不应该是默认设置。
如果我可以在不使用额外内存分配和复制操作的情况下执行此操作,为什么我应该使用 &&?
因为它允许您重载右值和左值的函数,并且每个函数都有不同的行为。您在两个重载中具有相同的行为,因此在这种情况下不需要右值引用。
更一般地说,右值引用参数允许您传递临时参数,同时允许从该参数移动。
为什么在这种情况下使用 &&&,这对我有什么帮助?
它允许您在参数为右值时打印"rvalue"
。
为什么不直接存储getValue的返回并打印出来呢?
然后,您将无法打印右值的"rvalue"
和左值的"lvalue"
。
除了移动构造函数/赋值运算符之外,没有多少情况是值有用的。
- 在 const 函数中通过引用和指针返回之间的区别
- 返回常量对象引用 (getter) 和仅返回字符串有什么区别?
- 引用捕获和在 lambda 中通过引用发送参数有什么区别 (C++)
- 在 Rust 中,指针和引用有什么区别?
- 常量引用和引用之间的区别
- 按值和引用传递指针之间的区别?
- C++ 对非常量对象的常量引用和对非常量对象的非常量引用之间的区别
- 普通的右值引用和 std::forward 返回的引用有什么区别?
- 右值引用和左值引用有什么区别?
- 当我使用按引用返回时,我不知道这些代码之间的区别
- 左值引用和右值引用之间的区别
- 通过引用传递对象和基元之间的区别
- lambda 表达式中引用捕获的 constexpr 变量和非显式捕获的 constexpr 变量之间的区别
- 将函数的引用和 lambda 表达式作为参数传递时有什么区别?
- 返回右值引用和 &&限定函数中的值之间的区别
- C++ - 将一个变量分配给另一个变量和将变量分配给引用变量有什么区别?
- 通过命名成员调用虚拟与地址或引用的区别
- DLL 引用之间的区别?和用途?
- 通过函数指针调用函数 - 是否取消引用指针?有什么区别?
- 句柄、指针和引用之间有什么区别