为什么在复制构造函数中分配联合成员会崩溃?
Why does assigning a union member in the copy constructors crash?
我正在编写一个 class,它通过联合存储几种数据类型之一(在本例中为 QBrush
和 int
),并通过使用 [= 记住哪个是活动的14=] 成员.
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提供的一些class。我猜崩溃与此 class 的内部结构有关。但我不知道。有人知道这是怎么回事吗?
这是一个错误:
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
。
我强烈建议您使用 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
构造函数抛出异常,我们就可以避免在展开时调用它的析构函数。
我正在编写一个 class,它通过联合存储几种数据类型之一(在本例中为 QBrush
和 int
),并通过使用 [= 记住哪个是活动的14=] 成员.
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提供的一些class。我猜崩溃与此 class 的内部结构有关。但我不知道。有人知道这是怎么回事吗?
这是一个错误:
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
。
我强烈建议您使用 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
构造函数抛出异常,我们就可以避免在展开时调用它的析构函数。