【问题标题】:C++ member initializer list for member array of non-copyable objects不可复制对象的成员数组的 C++ 成员初始值设定项列表
【发布时间】:2021-02-01 11:55:27
【问题描述】:

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

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 声明了析构函数。如果没有析构函数,则可以正确编译。如何让它为具有析构函数的类编译?

【问题讨论】:

  • 能否请您添加编译器错误?

标签: c++ constructor initializer-list


【解决方案1】:

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

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 对象(而不是int 以转换为Foo),并且不需要移动/复制。

【讨论】:

  • 您好,感谢您的回复。选项 3 编译,但前提是 Foo 的析构函数是隐式的。一旦我在类中添加~Foo(); 的声明(有或没有定义),它就会再次开始抱怨使用已删除的复制构造函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-25
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 2018-12-18
  • 2011-12-01
相关资源
最近更新 更多