[英]C++ - union with nontrivial class member type?
我正在使用一個聯合,該聯合的成員是使用菱形繼承的類,但程序在分配給該成員時遇到分段錯誤。
我的懷疑是我需要添加一些復制構造函數,但是經過多次嘗試,正確的方法仍然回避我。
我在這里包含了一個最小的、可重現的示例。
struct Base
{
Base() : a(0) {}
Base(int x) : a(x) {}
int a;
};
struct Derived1 : virtual public Base
{
Derived1() {}
};
struct Derived2 : virtual public Base
{
Derived2() {}
};
struct Final : public Derived1, public Derived2
{
Final() {}
};
union Example
{
Final value;
int i;
};
int main()
{
Example example{ Final() };
example.i = -1;
/* Segfault on the line below.
* If the above line
example.i = -1;
* is removed, the segfault is not encountered. */
example.value = Final();
}
我感謝任何知道如何做到這一點的人。
由於Base
類是virtual ,很可能有一些內部控制結構,當您分配時,它們會被破壞
example.i = -1;
當您重新創造value
,例如
new(&example.value) Final();
example.value = Final();
在分配之前,分段錯誤消失。 雖然,我不會推薦這個黑客。
正如評論中已經提到的,如果您有 C++17 可用,則std::variant
會更合適。 該示例將變為
std::variant<Final, int> example{ Final() };
example = -1;
example = Final();
從 c++11 開始,允許具有定義自己的構造函數和/或復制控制成員的成員的聯合,但是當聯合具有內置類型的成員時,我們可以使用普通賦值來更改聯合持有的值,但不適用於具有非平凡類類型成員的聯合。 當我們在類類型的成員之間來回切換聯合的值時,我們必須構造或銷毀該成員。 例如見波紋管代碼
#include <iostream>
#include <new> // for placement new
class Type // non built in type with constructors
{
private:
int val;
public:
Type() : val{0} { }
explicit Type(int v) : val{v} { }
Type(const Type &obj) : val{obj.val} { }
int getval() { return val; }
};
class unionexample // I enclose union with class for readability
{
private:
enum { INT,TYPE } OBJ;
union
{
Type Tval; // non build in type
int ival; // build in type
};
public:
unionexample() : ival{0}, OBJ{INT} // default with int
{ }
unionexample(const unionexample &obj) : OBJ{obj.OBJ}
{
switch (obj.OBJ)
{
case INT:
this->ival = obj.ival;
break;
case TYPE:
new (&this->Tval) Type(obj.Tval);
break;
}
}
unionexample &operator=(int v)
{
if (OBJ == TYPE)
{
Tval.~Type(); // if it is TYPE destruct it
}
ival = v; // assign
OBJ = INT;
return *this;
}
unionexample &operator=(Type v)
{
if (OBJ == TYPE)
{
Tval = v; // if it is alderdy Type just assign
}
new (&Tval) Type(v); // else construct
OBJ = TYPE;
return *this;
}
void print()
{
switch (OBJ)
{
case INT:
std::cout << "ival = " << ival << std::endl;
break;
case TYPE:
std::cout << "Tval = " << Tval.getval() << std::endl;
break;
}
}
~unionexample()
{
if (OBJ == TYPE) // if it is TYPE we must destruct it
Tval.~Type();
}
};
int main()
{
unionexample ue;
ue.print();
ue = Type(1);
ue.print();
}
輸出:
ival = 0
Tval = 1
在你的情況下
int main()
{
Example example{ value : Final() }; // construct with Final
example.value.~Final(); // destruct Final
example.i = -1; // assign int built in type
new(&example.value) Final(); // construct
example.value.~Final(); // destruct finally
}
如果你問這個問題而不是學習目的,你可以像其他答案一樣使用std::variant
。
謝謝。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.