使用私有复制/移动构造函数进行聚合初始化

时间:2011-06-08 13:50:48

标签: c++ gcc c++11 initialization

我在初始化聚合时测试another question的一些内容时遇到了这个问题。我正在使用GCC 4.6。

当我使用列表初始化聚合时,所有成员都在适当的位置构建,无需复制或移动。即:

int main()
{
  std::array<std::array<Goo,2>,2>
    a { std::array<Goo,2>{Goo{ 1, 2}, Goo{ 3, 4}} ,
        std::array<Goo,2>{Goo{-1,-2}, Goo{-3,-4}} };
}

让我们通过制作一些嘈杂的构造函数来确认:

struct Goo
{
  Goo(int, int) { }
  Goo(Goo &&) { std::cout << "Goo Moved." << std::endl; }
  Goo(const Goo &) { std::cout << "Goo Copied." << std::endl; }
};

运行时,不会打印任何消息。但是,如果我将移动构造函数设为私有,则编译器会向‘Goo::Goo(Goo&&)’ is private抱怨,尽管显然不需要移动构造函数。

是否有人知道移动构造函数是否有标准要求可以像这样进行聚合初始化?

2 个答案:

答案 0 :(得分:8)

不调用副本或移动构造函数是标准特别允许的优化(但不是必需的)。

为了在编译器之间保持一致,实现必须检查构造函数是否可以被调用,如果它不关心优化它。

答案 1 :(得分:0)

请允许我在GCC 4.6中再次通过修改后的案例跟进Bo的回答:

struct Goo
{
  Goo(int x, unsigned int n) : x(x), s(new char[n]) { }
private:
  Goo(const Goo &);
  Goo(Goo &&);
  int x;
  char * s;
};

struct Foo
{
  int a;
  Goo g;
};

void f()
{
  Foo k { 3, {1,2} }; // works
  //Foo t { 1, Goo{5,6} }; // fails
  //Foo r { 0, Goo(7,8) }; // fails
}

为什么第一种就地构造形式确定即使没有可访问的复制/移动构造函数(注意Goo显然不是POD或聚合),但后两者(功能上)相同的)形式不是?标准的哪一部分说编译器必须在后两种情况下检查可访问的构造函数,而不是在第一种情况下?