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