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

Aggregate initialization with private copy/move constructors

本文关键字:初始化 构造函数 移动 专用 复制      更新时间:2023-10-16

我在为初始化聚合的另一个问题测试一些东西时遇到了这个问题。我使用的是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; }
};

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

有人知道移动构造函数是否有这样的聚合初始化可访问的标准要求吗?

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

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

请允许我在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或聚合),即使是,第一种形式的就地构造也可以,但后两种(功能相同)形式则不然?标准的哪一部分规定编译器必须在后两种情况下检查可访问的构造函数,而不是在第一种情况下?