当调用移动构造函数和默认构造函数时

When dose move constructor and default constructor called

我有这个代码

class MyString {
    public:
        MyString();
        MyString(const char*);
        MyString(const String&);
        MyString(String&&) noexcept;
        ...
};

String::String()
{
    std::cout << "default construct!" <<std::endl;
}

String::String(const char* cb)
{
    std::cout << "construct with C-char!" <<std::endl;
    ...
}


String::String(const String& str)
{
    std::cout << "copy construct!" <<std::endl;
    ...
}

String::String(String&& str) noexcept
{
    std::cout << "move construct!" <<std::endl;
    ...
}

main()

MyString s1(MyString("test"));

我以为结果是这样的:

construct with C-char! <---- called by MyString("test")
move construct! <---- called by s1(...)

但我得到的是:

construct with C-char! <---- maybe called by MyString()

我想的步骤

  1. MyString("test") 使用带 char*
  2. 的构造函数构造一个右值
  3. 构造s1(arg)
  4. 因为arg是右值,s1应该用移动构造函数来构造 但是我发现如果没有 std::move.
  5. 就不会调用移动构造函数

为什么会这样?
如何在没有 std::move() 的情况下使用移动构造函数?

编译器:
Gnu C++ 9.3.0

Why is that happening?

C++17 起:因为 MyString("test") 是一个纯右值,并且语言说 s1 在这种情况下直接从 "test" 初始化。

C++17 之前:因为移动(和复制)构造函数的副作用不会 required/guaranteed 发生,这允许编译器通过不创建临时对象来进行优化。这种优化称为 copy elision,这就是您的编译器在此处所做的。

How to use move constructor without std::move()?

您不应该使用移动构造函数。最好不要创建多余的临时对象。您观察到的比您预期的要好。

如果您确实需要 std::move(此处不适用),您不应该避免使用它。

因此,问题类似于“如何在不使用适当工具的情况下让我的管道泄漏?”。 1. 您不想让您的管道泄漏,并且 2. 如果您出于某种原因这样做,请使用适当的工具。