为什么使用 Move 构造函数而不是复制?

why move constructor being used instead of copy?

提问人:Lion's_Den 提问时间:4/2/2021 最后编辑:Lion's_Den 更新时间:4/2/2021 访问量:435

问:

为什么调用移动构造函数而不是复制构造函数?当我删除移动构造函数时,则称为复制构造函数。

使用 : -fno-elide-constructors 以避免复制省略

#include <iostream>
class test
{
public:
    int x;
    char y;
    bool t;
    test()
    {
        std::cout << " constructed" << std::endl;
    }
    test(test &&temp)
    {
        std::cout << "move constructor" << std::endl;
    }
    test(const test &temp)
    {
        std::cout << "copy constructor" << std::endl;
    }
    template <typename... Args>
    static test create(Args... x)
    {
        test b(x...);
        return b;
    }
};
int main()
{
    test z = test::create();
    test v = test();
}

输出:

 constructed
move constructor
move constructor
 constructed
move constructor

上述原因可能是什么?

C++ 构造函数 移动语义复制 省略

评论

0赞 Alan Birtles 4/2/2021
为什么这让你感到惊讶?临时值在分配时会自动移动
1赞 Marius Bancila 4/2/2021
这很有趣。你用的是什么编译器?我本来希望复制省略可以工作,所以唯一的输出应该是“构造的”。
2赞 mch 4/2/2021
我试过了:godbolt.org/z/8EcbbTKf5 gcc 和 clang 打印,即使是几年前的版本。constructed constructed
0赞 zkoza 4/2/2021
你会期待什么行为?您希望在哪里调用复制构造函数,为什么?对我来说,这里唯一有趣的是,您的问题的标题不是“为什么使用移动构造函数而不是省略?
0赞 Lion's_Den 4/2/2021
@MariusBancila 我明确使用了“-fno-elide-constructors”

答:

0赞 sucksatnetworking 4/2/2021 #1

我以为这是基本的移动语义。将临时变量分配给非临时变量时,只要存在移动运算符(默认或指定使用),就会使用它。请看Klaus Igelberger的演讲。我认为是 cppcon 2019。 -道歉。我的意思是回答而不是回答

1赞 Jarod42 4/2/2021 #2

https://en.cppreference.com/w/cpp/language/return#Automatic_move_from_local_variables_and_parameters 开始,这主要是 NRVO 的后备:

然后重载 resolution 以选择要用于初始化返回值 [..] 的构造函数执行两次:

  • 首先,就好像表达式是右值表达式一样(因此它可以选择移动构造函数),以及 如果第一次过载解决失败,或者

[...]

因此,当 copy/move 没有被省略时,将执行 move-constructor(如果可用)。return b;

对于 ,是一个右值,并且在 C++17 之前,将使用 move 构造函数(如果未省略)(如果可用)。test v = test();test()

在 C++17 中,甚至不会创建临时函数,这将避免移动构造函数(主要是复制/移动省略版本,除了复制/移动不必可访问)。

如果删除 move-constructor,则在提供 copy-one 时,不会生成 move-one,并且只有 copy-constructor 可用,并用于代替 move-constructor。