不可复制对象的成员数组的 C++ 成员初始值设定项列表 1.使用 C++172.提供移动构造函数3.用大括号包裹每个数组元素

问题描述

我有一个不可复制的对象,它需要一个参数给它的构造函数

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

  private:
    int member;
};

Foo::Foo(int x) : member(x)
{
}

我有一个类,它包含这样的对象数组作为成员:

class Bar
{
  public:
    Bar(int a);

  private:
    Foo members[4];
};

假设我的对象 Foo 实在是太大了,而且它的构造函数太复杂了,以至于临时或重复的副本根本不存在,或者对于数组的每个项目,构造函数都不能被多次调用

如何为包含类编写构造函数以将参数传递给成员数组中的项?

我试过了:

Bar::Bar(int a) : members { a,a+1,a+2,a+3 }
{
}

g++ 说“use of deleted function Foo::Foo(const Foo&)”。

[编辑] 我也试过:

Bar::Bar(int a) : members { {a},{a+1},{a+2},{a+3} }
{
}

按照 Yksisarvinen 的建议。这也表示“use of deleted function Foo::Foo(const Foo&)”,但前提是我为 Foo 声明了析构函数。没有析构函数,它可以正确编译。如何让它为具有析构函数的类编译?

解决方法

这里有三个选项,取决于您实际想要做什么:

1.使用 C++17

C++17 有 guaranteed copy elision,可以解决这个问题。

2.提供移动构造函数

编译器选择复制构造函数,因为通过声明您自己的复制构造函数,您可以防止生成移动构造函数的可能性。根据您的实际类,移动构造函数可能可行,也可能不可行。

Foo(Foo &&) = default; //or implement "stealing" of the resource here

请注意,通过 rule of five,您还应该提供复制/移动赋值运算符和析构函数(默认与否)。

3.用大括号包裹每个数组元素

如果上述选项均无效,则解决方法是简单地将每个数组元素包装在其自己的一组大括号中

Bar::Bar(int a) : members { {a},{a+1},{a+2},{a+3} }

一般来说,您之前的选项依赖于从 intFoo 的转换。编译器完成转换后,它必须将转换后的对象复制(或移动,但您排除了它)到数组,这会触发错误。通过将它们包裹在大括号中,元素被初始化为 Foo 对象(而不是将被转换为 intFoo),并且不需要移动/复制。