通过 value/reference/rvalue 使用 std::move(str) arg

Pass by value/reference/rvalue with a std::move(str) arg

我有以下代码:

//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 当前设置为通过值参数传递,而不是通过右值引用传递。

When i is pass-by-value, d becomes empty,

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

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

只有用非 const 右值初始化对象才会导致参数被移出。在示例中,std::string i 被初始化为一个非 const 右值,移动构造函数将被调用。

As an aside why does the code in the current state compile if d is cast to an x-value?

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

I had thought if we had std::string i, a copy of the rvalue reference is made.

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

Also, if I observe that the output of d is still the same as prior to applying std::move, what does this mean in this case?

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

Does it mean that d is still occupying the space it originally occupied?

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

void func(const std::string &&i)

此签名不会移动任何内容,因为引用是对 const 对象的引用。删除 const,它将起作用。但前提是您再次在函数内 std::move 参数 i 。这是因为任何有名称的东西都是 lvalue,无论参数声明为 & 还是 &&。参见

void func(const std::string &i)

正如您可能已经知道的那样,这将被复制。但是,它的行为与 ptevious 类似,因为如果您在函数内放下 const 并执行 std::move( i ),它实际上会移动。这是因为,正如您所指出的,move 是一个强制转换,编译器会听取您的意见并完全按照您在强制转换时所说的去做,而不管您的意图如何。

void func(const std::string i)

这会在您的示例中移动,因为此处 i 是一个全新的字符串。外部字符串 d 被移入 i。但是,如果要将 i 移动到 val,您仍然必须删除 const 并使用 std::move( i )