如何使用已删除的复制构造函数初始化类数组(C ++ 11)

时间:2014-11-01 01:48:32

标签: c++ arrays c++11 gcc clang

关于Why can't I initialise an array of objects if they have private copy constructors?的现有问题具体涉及C ++ 03。我从那个问题中知道我在C ++ 03中不允许做的事情,但我认为它应该可以在C ++ 11中实现

我有一个不可移动的类(称之为Child),我需要在另一个类的构造函数中初始化一个Child数组(称之为Parent)。通过"不可移动"我的意思是Child对象的地址必须在该对象的生命周期内保持不变。这样做的正确方法是什么?

使用C ++ 11,我尝试了以下内容:

class Child
{
public:
    Child (int x) {}
    ~Child () {}

    Child (const Child &) = delete;
};

class Parent
{
public:
    Parent () : children {{5}, {7}} {}

private:
    Child children[2];
};

此代码与Clang 3.5.0编译良好,但GCC 4.9.1抱怨我正在尝试使用已删除的复制构造函数:

test.cc: In constructor ‘Parent::Parent()’:
test.cc:13:35: error: use of deleted function ‘Child::Child(const Child&)’
     Parent () : children {{5}, {7}} {}
                                   ^
test.cc:7:5: note: declared here
     Child (const Child &) = delete;
     ^

我已经了解了复制初始化和直接初始化(例如herehere)之间的区别,我想避免使用direct-来调用复制构造函数初始化。我的语法错了吗?这是GCC中的错误吗?或者我正在尝试做什么是不可能的?

2 个答案:

答案 0 :(得分:3)

我同意这似乎是GCC错误的评论(报告为63707)。

当数组中的类型具有用户定义的析构函数时,它只能编译,这对我来说没有意义。

答案 1 :(得分:-1)

我遇到了类似的问题,即这段代码

#include <iostream>

class Widget {
public:
    Widget(int i) { std::cout << "Ctor " << i << std::endl; }

    Widget(const Widget&); // = delete;
};

int main() {
    Widget w = 123;
}

编译并给出了预期的结果,但在取消注释= delete后,它无法使用gcc-4.9进行编译。

阅读标准后我相信,答案在于8.5/16中最高缩进的第二项,如下所述。

基本上似乎发生的事情是编译器在概念上想要通过副本创建临时类型Widget直接初始化来自该临时的实际对象w构造函数。由于复制构造函数被删除,编译停止。如果没有删除复制构造函数,编译器后来会意识到它可能会删除副本,但它没有那么远。

以下是相关部分:

  

[...] [...]复制初始化案例[...]用户定义的转换序列可以从源类型转换为目标类型[...],如上所述进行枚举13.3.1.4,通过重载决议(13.3)选择最好的一个。 [...]选择的函数以初始化表达式作为参数调用;如果函数是构造函数,则调用初始化目标类型的cv-nonqualified版本的临时函数。 [...]然后,根据上面的规则,使用调用的结果(这是构造函数的临时情况)直接初始化作为复制初始化目标的对象。在某些情况下,允许实现通过构造该实现来消除此直接初始化中固有的复制   中间结果直接进入被初始化的对象;见12.2,12.8。

但我可能错了,因为[...]部分有很多我不理解的地方。