为什么复制构造函数被强制移动"移动"对象有一个"非平凡的"工会会员?

时间:2017-11-04 00:29:03

标签: c++ c++14 move unions

我注意到#include <iostream> #include <sstream> void f(const char * str) { std::cout << str << std::endl; } std::string str(void (*populate)(std::ostream &)) { std::ostringstream stream; populate(stream); return stream.str(); } int main(int argc, char * * args) { f(str([](std::ostream & ss){ ss << "Value: " << 5; }).c_str()); return 0; } // g++ -std=c++11 main.cpp -o main // ./main // Value: 5 可以应用于与&#34;非平凡&#34; (完全不知道,但例如原始类型很好)成员。例如,以下代码编译(C ++ 14,Clang):

move

请注意,复制构造函数已删除。由于#include <vector> #include <string> class Foo { public: union { int i; bool b; }; Foo() {}; ~Foo() {}; // Move constructor to default. Foo(Foo &&) = default; // Copy constructor deleted. Foo(const Foo &) = delete; }; int main() { std::vector<Foo> v; v.push_back(Foo()); } std::vector可以接受右值引用,因此在这种情况下将使用它,并且不会发生push_back。然而,一旦&#34;非平凡&#34;类型被添加到联合中,强制复制构造函数 - 因此它不会编译:

copy

编译器错误消息的相关部分:

#include <vector>
#include <string>

class Foo {
public:
  union {
    int i;
    bool b;
    std::string s; // <-- Added element causing compile error.
  };

  Foo() {};
  ~Foo() {};

  // Move constructor to default.
  Foo(Foo &&) = default;

  // Copy constructor deleted.
  Foo(const Foo &) = delete;
};

int main() {
  std::vector<Foo> v;
  v.push_back(Foo());
}

我知道有关可以移动的内容和不可移动的内容的一些规则,但这似乎无关紧要。为什么会发生这种情况,如何解决这个问题,因此它不会调用复制构造函数?

目标编译器是Clang C ++ 14。

1 个答案:

答案 0 :(得分:2)

它试图调用您的复制构造函数,因为您的移动构造函数已删除。哦,当然,我知道你写过= default。但是由于union包含一个带有非平凡移动/复制构造函数的类型,如果不是用户提供的,union的复制/移动构造函数将被隐式删除。

并且= default没有提供&#34;用户提供&#34;。

换句话说,如果编译器的任何成员需要复制/移动union以外的代码,编译器就不能给memcpy一个复制/移动构造函数(又名:不是平凡的可复制的)。因此,包含union的类型也不能具有编译器生成的复制/移动代码。在这些情况下,您必须决定如何复制/移动对象。

这样的复制/移动构造函数需要知道它是哪种类型。