我正在编写一个类,它通过union(在这种情况下为QBrush
和int
)存储多种数据类型之一,并使用type
成员记住哪些是活动的。< / p>
class X
{
public:
X(const QBrush &brush)
: type(0), b(brush) { }
X(int integer)
: type(1), i(integer) { }
X(const X &other)
: type(other.type)
{
if (type == 0)
b = other.b;
else i = other.i;
}
~X() { }
private:
int type;
union
{
QBrush b;
int i;
};
};
int main(int argc, char *argv[])
{
X x = X(QBrush(Qt::red));
X y = X(x);
return 0;
}
我很惊讶这个程序崩溃了。目前我没有调试器,所以我只知道在分配画笔时它在X
的复制构造函数内崩溃了。请注意,当我用
X(const X &other)
: type(other.type), b(other.b), i(other.i)
{ }
这对我来说更加困惑。
QBrush
是Qt提供的一些课程。我想崩溃与这个班级的内部有关。但我不知道。有人知道发生了什么吗?
答案 0 :(得分:2)
这是一个错误:
X(const X &other)
: type(other.type)
{
if (type == 0)
b = other.b; // b is not constructed yet
else i = other.i;
}
b
尚未构建,但您可以在其上调用operator=
。
使用new(&b) QBrush(other.b)
,它使用复制构造函数正确构造b
。
答案 1 :(得分:2)
我强烈建议您使用boost::variant<QBrush, int>
/ std::variant<QBrush, int>
(C ++ 17),而不是尝试自己管理。在工会中放置非POD类型时,必须手动处理构造和销毁,并且您目前缺少一些案例。至少,您需要一个自定义析构函数,而规则3表示除了复制构造函数之外,还应该提供赋值运算符。
X(const X &other) : type(1) {
*this = other;
}
~X() {
if (type == 0) b.~QBrush();
}
X& operator=(const X &other) {
if (type == 0) b.~QBrush();
type = 1;
if (other.type == 0) {
new(&b) QBrush(other.b);
type = 0;
} else i = other.i;
return *this;
}
在这里,我转移了type
的赋值,这样如果QBrush
构造函数抛出异常,我们就会避免在展开时调用析构函数。