|
Boost : |
From: Hamish Mackenzie (boost_at_[hidden])
Date: 2002-02-06 10:37:29
I have uploaded move.tar.gz which implements some of these ideas.
http://groups.yahoo.com/group/boost/files/move.tar.gz
I have not had time to test it properly but let me know what you think.
One thing that is probably important is adding overloads that take the
allocator to use as an argument
template< typename T, class Allocator >
inline move_construct( T &, Allocator a );
etc.
On Wed, 2002-02-06 at 00:34, Howard Hinnant wrote:
> It isn't in the standard. About the closest thing is allocator has a
> member called construct:
Dang! I should have read the warning at the top of the gcc header file.
It says it was provided for backwards compatibility with HP STL (that
brings back memories of first trying to come to grips with STL)
> > The default move( T &, T & ) would be implemented using swap (which in
> > most cases is no throw). For scalar types it would use assignment.
>
> Implementing move with swap is needlessly inefficient. Ok, we can
> specialize it for scalars to not be inefficient. What about user
> defined PODS? Maybe with is_POD we could further specialize it. But
> even for something like std::string it is slower than need be. Sure, it
> is a lot faster than assignment. But it is twice as slow as it needs to
> be.
But would you agree that swap is the fastest way to move existing
containers such as std::vector and std::string (ie. without changing
them)?
Perhaps we could make the default to use copy construction and
assignment and specialize to use swap for containers?
I feel swap has at least two advantages though
1) People who have read Herb's "Exceptional C++" already know the value
of swap so it exists (or should) for most complex objects.
2) It can provide no-throw garantee easily
> I think any object with a non-trivial move should be expected to provide
> move semantics if it expects to move. A trivial move is one that works
> as a non-throwing copy. We do this already with copy. If you want to
> copy, and the compiler generated copy doesn't work right, you've got to
> roll up your sleeves and provide it. Relying on swap for move is
> backwards (due only to history). If a class provides proper move
> semantics, then it need not also specializing swap as swap can be
> programmed to detect and use move at no efficiency loss.
I think the class designer should have the choice of using swap because
it is simpler (in my opinion). The interation with the destructor is
hard to get wrong. Consider
class x
{
int ptr_;
public:
x() : ptr_( 0 ) {}
~x() { if( ptr_ ) delete ptr_; }
...
x( move_source< x > src ) : ptr( src.get().ptr_ ) {}
};
Failing to set src.get().ptr_ = 0 in the move constructor is a design
error that is hard to make if eaverything is done with swap.
> 2. How does one detect if an object implements move semantics (in
> templated code)?
We could add something to move_traits< T > to indicate how move will
behave. It could indicate if move is no-throw. Unfortunately it will
require the class designer to provide the information in some way.
> 3. How does one move from a temporary?
Hmm...
T f();
T dest;
move_to( dest ) = mover_from( f() );
Will fail to compile (for good reason). But compilers should do a good
job with return values so
T temp( f() );
move_to( dest ) = move_from( temp );
Should be just as fast.
Hamish Mackenzie
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk