C ++ 11右值引用vs const引用

问题描述 投票:4回答:5

这可能是显而易见的,但我认为这对我来说很难。鉴于这种:

void test(std::string&&) { }

std::string x{"test"};
test(std::move(x)); // ok

此代码使用右值引用作为参数调用test(),以便程序按照我的预期进行编译。

现在看看这个:

void other_test(const std::string&) { }

std::string x{"test"};
other_test(std::move(x)); // ok???

在这里,我倾斜了。为什么这个版本会编译? std::move返回一个&&类型;为什么我在使用const&的第二种方法中没有出错?


我知道

int&& s = 5;
const int& s = 5;

是有效的,因为在这两种情况下我提供的东西都没有左值,它没有地址。 &&const&相当吗?如果不是,有区别吗?

c++ c++11
5个回答
11
投票

std::move实际上并没有移动任何东西。对于T&&的演员而言,这只是一个奇特的名字。像test一样调用test(std::move(x));只表明T&&可以隐式转换为const T&。编译器看到test只接受const T&所以它将从T&&返回的std::move转换为const T&,这就是它的全部内容。


7
投票

简单来说:

  • &&可以绑定到非const rvalues(prvalues和xvalues)
  • const &&可以绑定到rvalues(const和非const)
  • &可以绑定到非const值左右
  • const &可以绑定到rvalues(prvalues和xvalues)和lvalues(const和非const)。又名任何事情。

2
投票

如果您希望函数明确允许const-Lvalue对象,但明确禁止Rvalue对象,请按如下方式编写函数签名:

void test(const std::string&) { }
void test(std::string&&) = delete;//Will now be considered when matching signatures

int main() {
    std::string string = "test";
    test(string);//OK
    //test(std::move(string));//Compile Error!
    //test("Test2");//Compile Error!
}

2
投票
test(std::string&& a) {
  something(a) //--> not moved because it has lvalue

变量名称是左值。 a是变量的名称,因此a是一个左值表达式,因此它不会被移动。

目前还不清楚你的意思是“有”。 a是一种表达方式。它是引用的名称,引用引用对象。值类别与表达式有关,而与对象无关。

test(const std::string& a):a是const lvalue reference,就像我有lv​​alue和rvalue之前一样。还有更多,在这种情况下,如果我打电话

std::move(a)

其中a是const&the move的作用!

如果“工作”意味着它调用移动构造函数或赋值,那么不,它不起作用,因为没有移动构造或赋值发生。


0
投票

当您调用std::move(x)时,将返回rvalue对基础数据的引用test。您可以将rvalue引用作为const(和const only!)引用参数传递,因为rvalue引用可以隐式转换为const引用。从函数的角度来看,它们可以说是相同的东西(只读参数)。如果删除了参数的const限定符,则此代码将无法编译:

void other_test(std::string&) { }
std::string x{"test"};
other_test(std::move(x)); //not okay because
//the function can potentially modify the parameter.

Bo Qian's youtube video on rvalue vs lvalue

© www.soinside.com 2019 - 2024. All rights reserved.