This code implements an unrestricted union which provides access by name and by index to any of its three members.
Since std::string
is non-trivially constructed and destroyed, I need to provide special constructor and destructor for the 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 ;
}
This example compiles and works fine (seemingly), but my questions are:
string
's constructor throws an exception? Does that need to be caught so as to not try to destroy an object that was never constructed? The code compiles in VC2015, which does support unnamed structs. Please disregard that detail.
Is it safe to do this?
No. First, the common initial sequence rule only allows reading of members, not writing:
In a standard-layout union with an active member (9.3) of struct type
T1
, it is permitted to read a non-static data memberm
of another union member of struct typeT2
providedm
is part of the common initial sequence ofT1
andT2
; the behavior is as if the corresponding member ofT1
were nominated.
Secondly, common initial sequence is a trait of standard layout types:
The common initial sequence of two standard-layout struct (Clause 9) types is [...]
and std::string
is not required to be standard-layout.
Is it safe to do this?
It depends on what you are willing to call safe. The code certainly invokes undefined behaviour by any reasonable interpretation of the standard.
You cannot read an inactive member of a union, except when there's a common subsequence involved (9.3 Unions), but these union members have no common initial sequence because the notion is only defined for two standard-layout structs (9.2 Class Members/20) and one member of the union is not a struct at all. It's an array so it cannot have a common initial sequence with anything.
This also applies to analogous code that uses primitive types, eg int x[3];
and struct {int x0, x1, x2};
. There's not even a guarantee that x2
and x[2]
have the same address.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.