C++拷贝,移动构造函数

too*_*zzy 3 c++ copy-constructor move-constructor c++11

我这里有代码:

#include <string>
#include <iostream>
#include <initializer_list>

template <typename T>
class Test
{
public:
  Test(std::initializer_list<T> l)
  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
  }

  Test(const Test<T>& copy)
  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
  }
  Test(Test&&) = delete;
  Test() = delete;
};

void f(const Test<Test<std::string>>& x)
{
  std::cout << __PRETTY_FUNCTION__ << std::endl;
}

void f(const Test<std::string>& x)
{
  std::cout << __PRETTY_FUNCTION__ << std::endl;
  f(Test<Test<std::string>>{x});
}

int main()
{
  Test<std::string> t1 {"lol"};
  f(t1);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我尝试用我的linux mint 19上的GCC 7.3.0编译这个命令:

g ++ -std = c ++ 11 -O0 test.cpp -o test -Wall -pedantic

编译失败,出现此调用错误:

f(Test<Test<std::string>>{x});
Run Code Online (Sandbox Code Playgroud)

需要移动构造函数,但它已被删除.我一直认为移动和复制构造函数在编译方面是等价的,因为rvalue可以绑定到const引用,但是在重载解析中优先使用明确定义的rvalue引用的重载.这是我第一次看到编译器实际上需要移动构造器,而不只是使用复制.为什么?我错过了什么吗?

Nat*_*ica 5

我一直认为移动构造函数和复制构造函数在编译方面是等效的,因为右值可以绑定到 const 引用,但使用显式定义的右值引用的重载只是在重载决策中优先考虑。

你的这个假设是正确的。const&如果您有一个采用 a和 a 的重载集,则如果您有右值,则&&&&版本将优先于。const&这里的问题是您的&&版本被标记为已删除。这意味着您明确声明您不希望从临时对象构建,并且代码将无法编译。

在这种情况下,如果您不希望班级可移动,那么您可以删除

Test(Test&&) = delete;
Run Code Online (Sandbox Code Playgroud)

由于用户定义的复制构造函数的存在将删除编译器自动生成的移动构造函数。


son*_*yao 5

您明确声明了移动构造函数并将其标记为delete,它将通过重载解析选择,然后导致错误.

如果同时提供了复制和移动构造函数,并且没有其他构造函数可行,则重载解析选择移动构造函数(如果参数是相同类型的rvalue(xvalue,例如std :: move的结果or a prvalue such as a nameless temporary (until C++17))),并选择复制构造函数如果参数是左值(命名对象或函数/运算符返回左值引用).

请注意,重载解析会忽略已删除的隐式 -declared移动构造函数,但显式声明的则不会.

重载解析会忽略已删除的隐式声明的移动构造函数(否则会阻止rvalue的复制初始化).(自C++ 14起)