【问题标题】:Aggregate initialization of class with noncopyable member具有不可复制成员的类的聚合初始化
【发布时间】:2015-12-19 07:56:29
【问题描述】:

假设我有一些删除了复制构造函数的类:

struct NoCopy
{
    NoCopy(int) {}
    NoCopy(const NoCopy &) = delete;
};

我在另一个类中使用这个类:

struct Aggregate
{
    NoCopy nc;
};

但是当我尝试使用聚合初始化时

int main()
{
    Aggregate a{3};
}

编译器输出如下错误:

error: use of deleted function ‘NoCopy::NoCopy(const NoCopy&)’

为什么聚合初始化需要类成员的复制构造函数?聚合初始化是否使用复制构造函数初始化所有成员?

【问题讨论】:

    标签: c++ c++11 aggregate-initialization


    【解决方案1】:

    你想要的正确语法是:

    Aggregate a{{3}};
    

    这为NoCopy 成员提供了一个初始化器。如果没有额外的{},编译器需要执行从intNoCopy 的转换(它很乐意通过非显式构造函数完成),然后使用它来构造nc。这通常会作为移动构造发生,但通过删除复制ctor,您也有效地删除了移动构造函数。

    一种更简单的思考方式可能是想象NoCopy 有一个带有两个参数而不是一个参数的值构造函数:

    struct NoCopy {
        NoCopy(int, int);
    };
    

    现在如果你写了

    Aggregate a{1, 2};
    

    这表明1 用于初始化nc2 用于初始化其他东西(编译时错误)。您必须添加额外的 {} 才有意义

    Aggregate a{{1, 2}};
    

    第三种方法是查看函数调用:

    struct NoCopy {
      NoCopy(int) {}
      NoCopy(const NoCopy &) = delete;
    };
    
    void fun(NoCopy) { }
    
    int main() {
      fun(1); // wrong
      fun({1}); // right
    }
    

    // wrong 版本中,使用NoCopy(int) 构造函数在调用点构造一个临时NoCopy 对象。然后将该临时值按值传递给fun,但由于NoCopy 不可复制,它会失败。

    // right 版本中,您为要构造的参数提供初始化列表。没有复制。

    【讨论】:

    • 谢谢,它有效。所以,这个问题的答案很简单,但是从编译器的信息中很难理解。
    • 顺便说一句,编译器忽略了这里的所有复制。因此,如果我在NoCopy 类中声明复制构造函数,它不会被调用,编译器无论如何都会直接调用NoCopy(int)
    • @anton_rh 是的,您得到的错误距离问题开始的地方只有几步之遥
    • @anton_rh 是的,但即使它忽略了副本,它仍然必须是合法的副本才能发生,替代方案将是一场灾难。
    猜你喜欢
    • 2020-05-15
    • 2015-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-13
    • 2020-05-23
    • 2016-06-23
    • 1970-01-01
    相关资源
    最近更新 更多