|
Boost : |
From: Anthony Williams (anthwil_at_[hidden])
Date: 2002-08-09 06:12:50
From: Itay Maman [mailto:itay_maman_at_[hidden]]
Sent: 09 August 2002 12:31
> Anthony Williams wrote in a message:
> >
> >I've just had a thought about how to implement the strong
> guarantee for
> variant, at the expense of larger space requirements --- have
> *two* copies
> of >the internals, with a flag to indicate which is valid. Then, when
> swapping or assigning, copy construct the value from the
> other variant into
> the unused >space, and destruct the original and switch the flag when
> everything is done.
>
> I don't think it is possible - in the general case - to
> create two identical
> instances of a class.
Sorry, that's not what I meant. The variant would have _storage_ for two
instances, but only contain one at a time. When swapping the variants, you
can copy-construct the other variant into the unused space in this variant,
then copy-construct this variant into the unused space in the other one. If
everything has succeeded, destruct the originals, and change the flags. If
anything failed, destruct the new copies (if any) and leave the flags alone.
Simple example, with a known type (untested):
class X{};
class Y
{
char buf1[sizeof(X)]; // ignoring alignment
char buf2[sizeof(X)];
bool useBuf1;
X& getVal()
{
if(useBuf1)
{
return *reinterpret_cast<X*>(buf1);
}
else
{
return *reinterpret_cast<X*>(buf2);
}
}
public:
Y(const X& val):useBuf1(true)
{
new (buf1) X(val);
}
~Y()
{
getVal().~X();
}
void swap(Y& other)
{
// copy the other into this one
if(useBuf1)
{
new (buf2) X(other.getVal());
}
else
{
new (buf1) X(other.getVal());
}
// now copy this into the other
try
{
if(other.useBuf1)
{
new (other.buf2) X(getVal());
}
else
{
new (other.buf1) X(getVal());
}
}
catch(...)
{
// destroy already-created copy
useBuf1=!useBuf1;
getVal().~X();
useBuf1=!useBuf1;
throw;
}
// OK, both copies succeeded, so destroy originals
// and change flags
getVal().~X();
useBuf1=!useBuf1;
other.getVal().~X();
other.useBuf1=!other.useBuf1;
}
Y& operator=(const Y& other)
{
// create a copy
if(useBuf1)
{
new (buf2) (other.getVal());
}
else
{
new (buf1) X(other.getVal());
}
// if that succeeded, destroy our original, and flip flag.
getVal().~X();
useBuf1=!useBuf1;
return *this;
}
};
Obviously, you need to account for alignment, and with variant it is a bit
more complex in the implementation due to the multiple types, but the idea
is the same.
Also, if you want assignment to actually perform assignment on the
underlying type, rather than just transfer the value into the variant, then
things are more complicated.
Anthony
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk