此代码实现了一个不受限制的联合,它通过名称和索引为其三个成员中的任何一个提供访问。
由于std::string
非常简单地构造和销毁,我需要为union
提供特殊的构造函数和析构函数。
#include <iostream>
#include <string>
using namespace std ;
union MyUnion{
string parts[3] ;
struct{ string part1, part2, part3 ; } ;
MyUnion(){
new(parts+0) string ; //constructs the 3 strings in-place
new(parts+1) string ;
new(parts+2) string ;
}
~MyUnion(){
parts[0].~string() ; //calls string's destructor
parts[1].~string() ;
parts[2].~string() ;
}
} ;
int main(){
MyUnion u ;
u.part1 = "one" ; //access by name
u.part2 = "two" ;
u.part3 = "three" ;
cout << u.parts[0] << endl ; //access by index
cout << u.parts[1] << endl ;
cout << u.parts[2] << endl ;
}
这个例子编译并且工作正常(貌似),但我的问题是:
string
的构造函数抛出异常怎么办?是否需要捕获它以便不试图破坏从未构造的对象?代码在VC2015中编译,它支持未命名的结构。请忽略这一细节。
答案 0 :(得分:2)
这样做是否安全?
没有。首先,常见的初始序列规则只允许读取成员,而不是写:
在具有结构类型
T1
的活动成员(9.3)的标准布局联合中,允许读取另一个的非静态数据成员m
提供T2
结构类型m
的联合成员是T1
和T2
的共同初始序列的一部分;行为就像提名T1
的相应成员一样。
其次,常见的初始序列是标准布局类型的特征:
两个标准布局结构(第9节)类型的公共初始序列是[...]
和std::string
不需要是标准布局。
答案 1 :(得分:0)
这样做是否安全?
这取决于你愿意称之为安全的东西。代码肯定通过对标准的任何合理解释来调用未定义的行为。
除非涉及共同的子序列(9.3 Unions),否则您无法读取联合的非活动成员,但这些联合成员没有共同的初始序列,因为该概念仅针对两个标准布局结构定义( 9.2集体成员/ 20)和工会的一个成员根本不是结构。它是一个数组,所以它不能有任何共同的初始序列。
这也适用于使用基本类型的类似代码,例如int x[3];
和struct {int x0, x1, x2};
。我们甚至不能保证x2
和x[2]
具有相同的地址。