为什么在std :: vector的初始化列表中调用复制构造函数?

时间:2016-04-05 08:21:40

标签: c++ move-semantics initializer-list

我有以下非常简单的课程:

class Foo 
{
public:
  Foo() {}
  Foo(const Foo&) = delete;
  Foo(Foo&&) {}

  void operator=(const Foo&) = delete;
  void operator=(Foo&&) {}

  void dump() const {}
};

该类是可构造和可分配的,但不是可复制构造和可分配的。

我想使用vector的初始化列表初始化Foo元素的向量。

std::vector<Foo> vf = { Foo() };

编译器抱怨,因为代码必须使用已删除的复制构造函数。任何人都可以解释一下,为什么在这种情况下不使用移动构造,以及为什么需要复制对象?

以下还需要复制构造函数,但不起作用:

std::vector<Foo> vf = { std::move(Foo()) };

另一方面,这工作正常(调用移动构造函数):

std::vector<Foo> vf;
vf.push_back(Foo());

感谢您的解释...... :)

更新

建议的this帖子解释了我的问题。

此外,让我们考虑以下代码(以及上面的class Foo):

class Bar {
public:
    Bar(std::initializer_list<Foo> _l) {
        std::cout << "Bar::Bar()" << std::endl;
        for (auto& e : _l)
            e.dump();
    }
};

int main() {
    Bar b { Foo() };
    return 0;
}

这将产生以下输出(使用C ++ 11编译):

Foo::Foo()
Bar::Bar()
Foo::dump()
Foo::~Foo()

可以看出,初始化列表实际上并没有填充大括号之间声明的“对象副本”。从C ++ 14开始可能不是这样。

3 个答案:

答案 0 :(得分:9)

具体是因为您使用initializer list使用了复制构造函数。初始化列表初始化为对象的 copy ,然后传递给向量。

如果您阅读链接引用,则从C ++ 14开始,它甚至明确地说

  

...每个元素都是 copy-initialized ...来自原始初始化列表的相应元素

强调我的

答案 1 :(得分:0)

std::initializer_list不适用于仅限移动类型。有关详细信息,请参阅this question

幸运的是,对你来说有一个简单的解决方法:

std::vector<foo> vf (1);

这将使用1个默认构造的foo初始化向量。

答案 2 :(得分:0)

一般而言,对std::vector元素施加的要求是元素类型是完整类型并满足Erasable的要求。因此,您的对象没有任何问题。

但是,使用初始化列表初始化如下:

std::vector<Foo> vf = { Foo() };

要求将列表中的临时对象Foo()复制到向量中。因此,编译器会抱怨,因为您已经使对象不可复制。

您可以通过以下方式完成您想要的任务;

std::vector<Foo> vf(1);