混淆右值和左值

Confused with r-values and l-values

我最近在 C++11 的白皮书上读到,如果我写,

void foo(X&)

这将针对左值而不是右值调用

如果我写,

void foo(const X&)

这将为 r 值和 l 值调用。

谁能给我举个例子,这是什么意思?

这个函数接受左值引用

void foo(X&)

尝试用右值调用它会产生错误。

此函数需要一个 const 左值引用

void foo(const X&)

但有一个问题:

An rvalue may be used to initialize a const lvalue reference, in which case the lifetime of the object identified by the rvalue is extended until the scope of the reference ends.

来自 cppreference

所以最后一个函数确实接受左值和右值参数

struct X {};

void foo(X&) {
}

void fooC(const X&) {
}

int main() { 
   X obj;
   // foo(std::move(obj)); // Error - non-const
   foo(obj); // Valid
   fooC(obj); // Valid
   fooC(std::move(obj)); // Valid
}

有关更多信息,请查看此处:reference initialization 或查看 [dcl.init.ref]/p5

考虑这段代码:

int i = 58;

什么是58?它是一个文字常量.

因此:foo (const int&)

58 是一个右值(在这种情况下也是一个文字常量),因为您不能直接引用它,比方说,修改它,因为没有办法这样做。你可以参考i,因为它有名字,有标识符,但是58本身没有标识符。

通俗地说,如果某物存在但没有声明的名称,您可以使用它访问它,那么它是一个常量和一个 r 值,除非您使用 r-val 引用 int&& 引用它,然后您可以改变它。

int f();
...
int x = f(); //the returned int is an r-value, but x is an l-value

当你像这样声明 foo 函数时

void foo(X&)

那么这样的代码将无法编译:

foo(5);

但是如果你这样声明:

void foo(const X&)

那么你可以这样称呼它:

foo(5);

const 文字 5 是一个右值,因为它没有名称。

粗略地说,右值是临时对象(从函数返回),而左值是您也可以引用的对象。

例如:

X bar();

X x = bar();

在该代码中(忽略可能的编译器优化),创建了一个临时 X 对象来保存 foo 的返回值并传递给 x 的复制构造函数,这个临时对象是一个右值,仅存在于此语句中,不能被代码的其他部分引用。 x不过是一个左值,你可以取回它的地址,以后再引用。

两种功能

void foo(X &);
void foo(const X &);

分别期望左值、非常量和常量。后者接受右值的原因是因为右值可以转换为对左值的常量引用。也就是说,你可以这样做:

const X &ref = bar();

这里 bar() 返回的临时变量直到 ref 超出范围才被销毁,因此它的生命周期已经延长到语句之外。但是你不能对非常量引用做同样的事情,

X &ref = bar(); // Error!

这是不允许的,因为 bar 的返回值是临时值(右值),无法修改。

但是请注意,这不是 C++11 的功能,它已经存在了。新功能是能够指定右值引用

void foo(X &&);
void foo(const X &&);

引入了更微妙的情况,例如 Universal References in C++11 - Scott Meyers