Re: Anonymous union rules against constructors & assignment
"Crosbie Fitch" wrote:
Anonymous union rules against members having constructors & non-default
assignment seem fairly arbitrary and unnecessary. :-)
template <>
class X
{
union
{ object d;
element<X,1> d1; // First pseudo member of d
element<X,2> d2; // Second pseudo member of d
};
};
..
X x,y;
x.d1=23; // Works fine element<> has operator=(int)
x.d2=123; // Fine
y.d1=5; // Fine too
y.d2=x.d1; // Fine - converts d2 to int
x.d2=y.d2; // Invokes default assignment operator :-(
The C std in its infinite wisdom says that members of an anonymous union can
do what the hell they want except they must not provide a default
constructor or assignment (or require a non-trivial assignment).
I neither want x.d2=y.d2 to do nothing, nor to do default assignment. What
can I do?
The only solution I've come up with is not really good enough, i.e.
template <>
class X
{
union
{ object d;
const element<X,1> d1;
const element<X,2> d2;
};
};
By adding const, and constifying the element::operator=(int) with a
const_cast to undo it, I can oblige a conversion rather than a default
assignment.
I can suffer the lack of constructors - that's fine. But, prohibiting
non-default assignment, WHY???
The C++ prohibition against union members having non-trivial
constructors, destructors or assignment operators makes perfect sense.
The reason is simply that it is the program's responsibility - not the
compiler's - to know which one of a union's members is currently
"active" - that is, which of its members was the last one assigned a
value. It should be clear that without this information, the only way
to make a copy a union safely is to require that none of its members
have a custom assignment operator - because the compiler will not know
to call it.
Furthermore, it should be just as clear that no object can be assigned
a value unless the assignment operator for that type is invoked.
Otherwise the consequences are likely to be disasterous. Imagine for
example a union that had a shared pointer (such as a
std::tr1::shared_ptr) as a member. After copying the union (without
invoking shared_ptr's assignment operator), the program would then have
two, identical shared pointers - but each with a use_count of 1. So
when either smart_ptr is destoyed, the other one will be invalidated
prematurely.
As a practical matter, C++ supports unions largely to be compatible
with C - and there is little reason to use them for much else. Because
as the restrictions concerning unions make clear - unions are not type
safe. And C++ usually supports alternatives to unions that are type
safe - inheritance and polymorphic pointers to name just two. And most
programming problems are solved best by thinking in terms of
requirements and not in terms of solutions. So the question is not how
to force a union to support behavior that it is entirely unsuited for -
the question is what exactly does the program have to do - and then to
frame the solution in terms of meeting those requirements.
And if a union is to be used, then the only approach is to eliminate
the non POD types. I would imagine that a union like the one below
could suffice:
int main()
{
union
{
char data[4];
struct
{
char d0;
char d1;
char d2;
char d3;
};
} x, y;
x.d1 = 23; // Works fine
x.d2 = 123; // Fine
y.d1 = 5; // Fine
y.d2 = x.d1; // Fine
x.d2 = y.d2; // Fine
}
Greg
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]