多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
# (广义的)联合体 在C++98(或更早)版本中,union的成员类型,必须不含自定义构造/析构函数或者赋值操作符。 ``` union U { int m1; complex m2; //错误(明显的):complex拥有构造函数 //错误(不那么明显):string的内部数据只能严格地由其构造函数, // 拷贝构造函数,和析构函数去维护 string m3; }; ``` 亦即: ``` U u; // 使用哪个成员的构造函数呢? u.m1 = 1; // 给整型成员赋值 string s = u.m3; //灾难:从string成员拷贝 ``` 显而易见,把值写入一个成员,之后又读取另外一个成员的做法是给自己找麻烦,然而人们往往并非刻意而为(多因失误导致) 。 C++11对union的限制条件进行了放宽,以允许更灵活广泛的成员类型。其中值得特别指出的是,带有自定义构造函数/析构函数的类型现在也可作为union的成员了。此外,为使“灵活”不至成为脱缰野马,新标准又特别引入了“第四条军规”(译注:参见下文),并倡导使用“可识别union”(译注:参见下文Widget样例以及Boost::Any和Boost::Variant)。 C++11中的对union的限制条件重新定义如下: * 不含虚函数(与C++98相同) * 不含引用成员(与C++98相同) * 没有基类(与C++98相同) * 若union的某个成员的类型含有自定义构造/拷贝/析构函数,那么该union的相应构造/拷贝/析构函数将会被自动“禁用”(译注:在C++11中我们可以使用delete关键字来“禁用”构造/析构函数),随之而来的后果是:该union不能被实例化成对象。(新增的所谓“第四条军规”) 例如: ``` union U1 { int m1; complex m2; // ok }; union U2 { int m1; string m3; // ok }; ``` 上述代码看起来容易出问题(译注:例如有人实例化了U2类型的对象并给其m1成员赋值之后,当union析构时,m3的析构函数可能会crash),但是有了第四条军规,刚才的隐含问题便迎刃而解(译注:通过编译错误)。即: ``` U1 u; // ok u.m2 = {1,2}; // ok:给complex成员赋值 U2 u2; // 编译错误: string类含有析构函数,因而U2的析构函数已被自动禁用 //(译注:析构函数被禁用意味着不允许在栈上实例化U2对象,否则无法析构) U2 u3 = u2; // 编译错误:string类含有拷贝构造函数, // 因而U2类型同样也不能被拷贝构造 ``` 这样看来,先前定义的U2几乎没什么实际用途了。唯一可能用到这种奇葩union的地方是,把它嵌到结构体里并且额外记录其“当值”成员类型——也就是所谓的“可识别union”。样例如下: ``` class Widget { // 用union存储的“三态”Widget private: // 用以实现“可识别union”的“当值”类型标记 enum class Tag { point, number, text } type; union { // 三态的具体存储形式 point p; // point类含有构造函数 int i; string s; // string类含有默认的构造/拷贝/析构函数 }; // ... // 由于string中存在拷贝函数,所以需要“手工拷贝”union Widget& operator=(const Widget& w) { // 译注:从text态到text态 if (type==Tag::text && w.type==Tag::text) { s = w.s; // 直接使用string的赋值运算符 return *this; } // 译注:从text态到其他态,意味着union不再用于存放string // 由于union的拷贝函数已被自动禁用, // 所以需要有人手工释放string原先所占资源 if (type==Tag::text) s.~string(); // 此处需要显式析构 switch (w.type) { case Tag::point: p = w.p; break; // 普通的拷贝 case Tag::number: i = w.i; break; // 译注:C++98/03标准中的的原地拷贝构造语法 case Tag::text: new(&s)(w.s); break; // placement new } type = w.type; return *this; } }; }; ``` 其他参考文献: * [N2544=08-0054] Alan Talbot, Lois Goldthwaite, Lawrence Crowl, and Jens Maurer: [Unrestricted unions (Revison 2)](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf) (翻译:张潇)