C++ 为什么std::为右值或常量左值函数参数移动复制内容?

C++ 为什么std::为右值或常量左值函数参数移动复制内容?,c++,move-semantics,C++,Move Semantics,如果我在当前作用域中的堆栈对象上使用std::move,则内容将移动到目标,而源为空 #include <iostream> #include <string> #include <utility> #include <vector> int main() { std::string str("stackoverflow"); std::vector<std::string> vec; vec.emplace

如果我在当前作用域中的堆栈对象上使用std::move,则内容将移动到目标,而源为空

#include <iostream>
#include <string>
#include <utility>
#include <vector>

int main()
{
    std::string str("stackoverflow");

    std::vector<std::string> vec;
    vec.emplace_back(std::move(str));
    std::cout << "vec[0]: " << vec[0] << std::endl;

    std::cout << "str: " << str << std::endl;
}
如果我对右值或常量左值函数参数使用std::move,则会复制内容

#include <iostream>
#include <memory>
#include <vector>
#include <utility>

void process_copy(std::vector<int> const & vec_)
{
    std::vector<int> vec(vec_);
    vec.push_back(22);
    std::cout << "In process_copy (const &): " << std::endl;
    for(int & i : vec)
        std::cout << i << ' ';
    std::cout << std::endl;
}

void process_copy(std::vector<int> && vec_)
{
    std::vector<int> vec(vec_);
    vec.push_back(99);
    std::cout << "In process_copy (&&): " << std::endl;
    for(int & i : vec)
        std::cout << i << ' ';
    std::cout << std::endl;
}

int main()
{
    std::vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    process_copy(std::move(v));

    std::cout << "In main: " << std::endl;
    for(int & i : v)
        std::cout << i << ' ';
    std::cout << std::endl;
    std::cout << "size: " << v.size() << std::endl;
}

为什么std::move的行为不同?

如果值绑定到一个变量,即使它声明为右值显示(
&&
),也需要使用
std::move
)。i、 e.应该是:

void process_copy(std::vector<int> && vec_)
{
    std::vector<int> vec(std::move(vec_));
    ...
}
void process\u copy(标准::向量和向量)
{
std::vec(std::move(vec));
...
}

如果值绑定到变量,即使它被声明为右值revefence(
&&
),也需要使用
std::move
)。i、 e.应该是:

void process_copy(std::vector<int> && vec_)
{
    std::vector<int> vec(std::move(vec_));
    ...
}
void process\u copy(标准::向量和向量)
{
std::vec(std::move(vec));
...
}

您的向量实际上是复制的,而不是移动的。原因是,尽管声明为右值引用,
vec
表示函数体内的左值表达式。因此,调用的是
std::vector
的复制构造函数,而不是移动构造函数。这样做的原因是,
vec\uu
现在是一个命名值,而右值不能有名称,因此它会折叠为左值。由于此原因,以下代码将无法编译:

void foo(int&& i)
{
    int&& x = i;
}

为了解决此问题,您必须再次通过调用
std::move(vec)
使
vec\u>匿名,您的向量实际上是复制的,而不是移动的。原因是,尽管声明为右值引用,
vec
表示函数体内的左值表达式。因此,调用的是
std::vector
的复制构造函数,而不是移动构造函数。这样做的原因是,
vec\uu
现在是一个命名值,而右值不能有名称,因此它会折叠为左值。由于此原因,以下代码将无法编译:

void foo(int&& i)
{
    int&& x = i;
}

为了解决此问题,您必须通过调用
std::move(vec)

再次使
vec\uz>匿名,记住
std::move
实际上并不移动任何东西。它只是一个转换到右值的引用。随后是否移动或复制该右值引用取决于上下文、对象是否实现移动操作以及源对象是否为
const
。相关:在第一个示例中,实际移动数据所有权的
是std::string的移动构造函数。在第二个示例中,您只是发送了一个右值引用。您可以在此处手动获取传递的std::vector的所有权。请记住,
std::move
实际上并不移动任何内容。它只是一个转换到右值的引用。随后是否移动或复制该右值引用取决于上下文、对象是否实现移动操作以及源对象是否为
const
。相关:在第一个示例中,实际移动数据所有权的
是std::string的移动构造函数。在第二个示例中,您只是发送了一个右值引用。您可以在此处手动获取传递的std::vector的所有权,需要注意的是,实际转移数据所有权的是move构造函数。在这种情况下,应该使用std::forward来提供更好的可读性,不是吗?@Klaus
vec\uuu
不是一个转发引用,所以我认为
move
更合适。@Klaus std::forward确实也可以工作,但我们应理解std::forward的目的,即“完美转发”。这里vec_uu是一个右值ref,所以最好直接使用std::move,这就是它的意思。@theWiseBro:好的,明白了!谢谢此外,,需要注意的是,实际转移数据所有权的是move构造函数。在这种情况下,应该使用std::forward来提供更好的可读性,不是吗?@Klaus
vec\uuu
不是一个转发引用,所以我认为
move
更合适。@Klaus std::forward确实也可以工作,但我们应理解std::forward的目的,即“完美转发”。这里vec_uu是一个右值ref,所以最好直接使用std::move,这就是它的意思。@theWiseBro:好的,明白了!谢谢