0

我有以下代码:

//void func(const std::string &&i){
//void func(const std::string &i){
void func(const std::string i){
  std::string val{i};
}

int main() 
{ 
  std::string d = "asdf";
  func(std::move(d));
  std::cout << d << std::endl;
} 

i是按值传递时,d变为空,但d如果我们通过引用或右值引用传递,则保留其形式。有人可以解释发生了什么吗?

我知道这std::move实际上并没有移动任何东西,而是通过将其转换为 xvalue 来使它所接收的变量可移动。

d顺便说一句,如果将当前状态的代码强制转换为 x 值,为什么会编译?func当前设置为通过值参数而不是通过右值引用传入。

4

2 回答 2

3

当 i 是传值时, d 变为空,

准确地说,d将处于 C++ 标准中未指定的某些有效状态。空是一种可能。

std::move它本身永远不会导致直接调用移动构造函数。将右值引用绑定到对象也不会导致直接调用移动构造函数。

只有使用非常量右值初始化对象才会导致参数被移出。在示例中,std::string i使用非常量右值进行初始化,并且将调用移动构造函数。

顺便说一句,如果将 d 强制转换为 x 值,为什么当前状态下的代码会编译?

因为该类型有一个(未删除的)移动构造函数。因此,参数可以从右值初始化。

我曾想过如果我们有 std::string i,就会制作一个右值引用的副本。

std::string i不是参考。它是一个类型的变量,std::string因此有一个类型的对象std::string与该变量相关联。该对象使用作为参数传递给函数的表达式进行初始化。

另外,如果我观察到 d 的输出仍然与应用 std::move 之前相同,那么在这种情况下这意味着什么?

如果您使用右值调用未注释的函数版本,则该参数将被移出。如果值与原来相同,则仅表示该值相同。您不能假设该值将相同,也不能假定它不会相同。

这是否意味着d仍然占据它原来占据的空间?

假设“空间”是指变量所在的存储空间,那么它当然仍然占用相同的存储空间。对象的地址在对象的生命周期内永远不会改变。

于 2020-04-21T13:56:45.023 回答
0
void func(const std::string &&i)

这个签名不会移动任何东西,因为引用是一个const对象。删除const,它会工作。但前提是您再次在函数内部输入std::move参数。i这是因为任何有名字的东西都是一个lvalue,无论参数被声明为&还是&&。看到这个答案

void func(const std::string &i)

正如您可能已经知道的那样,这将复制。然而,它的行为与之前的类似,如果你将constand do放到std::move( i )函数内部,它实际上会移动。这是因为,正如您所指出的,move它是一个强制转换,编译器会听您的话,并在您强制转换时完全按照您所说的去做,而不管您的意图是什么。

void func(const std::string i)

这在您的示例中移动,因为这里i是一个全新的字符串。外部字符串d被移动到i. 但是,const如果std::move( i )您想i进入val.

于 2020-04-21T14:03:29.973 回答