【问题标题】:Aggregate initialization with private copy/move constructors使用私有复制/移动构造函数进行聚合初始化
【发布时间】:2011-09-10 21:48:01
【问题描述】:

我在为 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&amp;&amp;)’ is private,尽管显然不需要移动构造函数。

有谁知道对于像这样的聚合初始化是否可以访问移动构造函数的标准要求?

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

    • §8.5.4/3 描述了为什么这是允许的。将其与§8.5/16/6/2 进行对比。 (迟到的反应怎么样?;-])
    • @ildjarn:非常感谢,虽然摘录会更好,所以我不必切换任务!
    • §8.5 确实很大——太大了,无法评论。 :-[
    • @ildjarn:很好地参考了§8.5/16/6/2!所以Foo k{3,{1,2}} 直接初始化了k.a(3)k.g(1,2),我们不需要不可访问的复制构造函数。
    • 公平地说,这也归功于 litb 让我了解这一点。 :-]
    【解决方案2】:

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

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

    【讨论】:

    • 谢谢!不过,我什至无法让 GCC 使用 -O0 调用移动构造函数——构造函数的选择取决于编译器,这并不奇怪吗?对了,为什么我不能说array&lt;Goo, 2&gt; a{{1,2}, {3,4}}?说Goo g{1,2};完全没问题。
    • @Kerrek - 就地优化的构造非常简单,gcc 即使在 -O0 时也能做到这一点,这是众所周知的。 Goo 有一个构造函数采用两个整数,所以它可以工作。 std::array 只有它的默认构造函数,它不接受那种形式的值。它需要一个来自 initializer_list 的构造函数。我相信对此有“错误报告”。
    • 我认为 std::array 被明确设计为聚合类型,因此它不能有任何用户定义的构造函数。我只是想知道为什么,鉴于它是一个聚合,我不能在聚合初始化中指定 {1,2} 并让它调用匹配的构造函数,就像 8.5.4 第 3 条一样。
    • @Kerrek - 这是关于大括号省略(或缺少大括号省略) - 例如,请参阅thisarray&lt;Goo, 2&gt; a{{{1,2},{3,4}}} 应该工作,但显然 gcc 在这方面有问题。
    • @Johannes:我发了一个后续——你是说后续场景如预期但是array&lt;Goo,2&gt; a{{{1,2},{3,4}}}的失败是GCC中的一个bug?
    猜你喜欢
    • 1970-01-01
    • 2016-08-17
    • 1970-01-01
    • 1970-01-01
    • 2020-05-06
    • 2018-10-23
    • 2014-09-07
    • 2012-10-10
    相关资源
    最近更新 更多