Perhaps i lost track how. Can you paste some sample elegant example? I
may be wrong but it feels like by using some sort of two-phase
construction with default constructor producing useless/invalid
object? There are cases when missing value is important, useful and
valid state of object (scientific computing). On other cases i usually
prefer a pointer that is NULL (or exception) to any ways to produce
invalid object with missing value. The placement news, swaps and
invalid state (when not natural) cause confusion to average
programmer, slow him down and i do not have time to maintain
everything myself.
Something along the lines of:
template< class T >
class DelayedBuilder
{
public:
DelayedBuilder():_valid(false){}
// ensure RAII
~DelayedBuilder(){
if(_isvalis)destroy();
}
// reinterpret union as T
T& value(){ assert(_isvalid); return *((T*)_data.object);}
// destroy object
void destroy(){ assert(_isvalid); value().~T(); }
// build object
void build()
{ assert(!_isvalid); new (_data.object) (); _isvalid = true; }
template<class P1> void build(P1 const & p1)
{ assert(!_isvalid); return new (_data.object) (p1); _isvalid =
true; }
template<class P1,class P2> void build(P1 const & p1, P2 const &
p2)
{ assert(!_isvalid); return new (_data.object) (p1,2); _isvalid =
true; }
// and so one for build functions
private:
union{ stricter_alignement ; unsigned char object[ sizeof(T) ] ;}
_data;
bool _isvalid;
};
And the usage:
// SocketStream has only constructor with (address,port)
DelayedBuilder<SocketStream> socket;
// try to build socket 3 times
for( int i=0; i<3 ; ++i )
{
try {
socket.build("127.0.0.23",4242);
} catch(SocketConnectError const & e){
continue;
}
...
}
if( !socket.isValid() )
{// failure
return -1;
}
// ... use socket
I don't say I would use it all over the place but it might have its
use.