Re: Initializing member references to dummy member variables
On Sunday, 18 August 2013 09:10:27 UTC+1, dar...@gmail.com wrote:
On Sunday, August 11, 2013 11:29:56 PM UTC-4, K. Frank wrote:
For your main problem: you need to use either an integer or a string. And
neither both together nor none at all; always exactly one. If you're using
C++11, this is a job for a union.
// Not tested
class Handle {
union MyData {
int i;
std::string s;
MyData( int i = 0 ) : i{ i } {}
MyData( std::string const &s ) : s{ s } {}
MyData( std::string &&s ) : s{ std::move(s) } {}
} data;
bool useStr;
public:
Handle( int i ) : data{ i }, useStr{ false } {}
Handle( std::string const &s ) : data{ s }, useStr{ true } {}
Handle( std::string &&s ) : data{ std::move(s) }, useStr{ true } {}
Handle( Handle const &that );
Handle( Handle &&that );
~Handle();
void swap( Handle &that );
Handle & operator =( Handle that )
{ this->swap(that); }
//...
};
In previous versions of C++, a union could not have a member
if any of its special member functions were non-trivial. All
of std::string's s.m.f.s are non-trivial, so you have to use
one of the aforementioned solutions if you're using a pre-11
compiler. For C++11, non-trivial types can be in a union, but
each special member function is deleted (i.e. cancelled)
unless all its members' versions of that s.m.f. is trivial.
Handle will start off with NO s.m.f.s available until we add
them in manually.
What does the destructor of the union do in this case? If the
last field used was the string, then it needs destruction; if
the last field used was the int, then destruction of the string
element would be undefined behavior. According to the standard,
if and non-static data member of the union has a non-trival
destructor, the corresponding member function of the union must
be user-provided or it will be implicitly deleted for the union.
Implicitly deleting a destructor means that the only thing you
can do with the resulting union is to allocate it dynamically,
and never delete it.
To use the union in a class, you need to provide a user defined
destructor. But don't ask me what it should do. It will have
to use an explicit destructor call to destruct the string
member, but only if the string member was the active member
(which is information it doesn't have).
In fact, what he needs isn't a union, but a variant (from
Boost, or hand written, if you can't use Boost); a discriminate
union, if you prefer.
For the rest: VC++ doesn't support this feature of C++11 yet,
so portability would be limited. With g++ 4.7.2, it does work
if I define the union as:
union U
{
int i;
std::string s;
U() : i() {}
~U() {}
};
and do everything with placement new/explicit delete on U::i or
U::s (exactly as you would if you were implementing Variant
yourself). Globally, this feature does make the implementation
of Variant somewhat cleaner---you loose a lot of
reinterpret_cast, and additional members necessary to
(hopefully) ensure alignment. But it probably shouldn't appear
elsewhere; it's too tricky to get right.
--
James