为什么在复制构造函数中分配union成员会崩溃?

时间:2017-11-07 18:51:09

标签: c++ constructor copy-constructor unions

我正在编写一个类,它通过union(在这种情况下为QBrushint)存储多种数据类型之一,并使用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提供的一些课程。我想崩溃与这个班级的内部有关。但我不知道。有人知道发生了什么吗?

2 个答案:

答案 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构造函数抛出异常,我们就会避免在展开时调用析构函数。