This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Implementing clean and simple move symantics


Hopefully the title of this e-mail won't be too strong!

After looking at various methods of implementing move symantics, the way I personally like the best looks like:

//Set this to 1 for types you want to be moveable
 template<typename _Tp>
   struct _Moveable
   { enum {_M_type = 0}; };

//Simple wrapper class
 template<typename _Tp>
 struct _MoveWrapper
 {
   _Tp& __wrapped;
   _MoveWrapper(_Tp& __wrapped_in) : __wrapped(__wrapped_in)  { }
 };

//Helper for __move function for when type is not moveable
 template<typename _Tp, int _Int = _Moveable<_Tp>::_M_type>
 struct _MoveReturnType
   { typedef _Tp& _Type; };

//Helper for _move function for when type is moveable
 template<typename _Tp>
   struct _MoveReturnType<_Tp, 1>
   { typedef _MoveWrapper<_Tp> _Type; };

// Denotes an object can be moved.
 template<typename _Tp>
   typename _MoveReturnType<_Tp>::_Type __move(_Tp& __moved)
   { return __moved; }


For most types T , using this involves 2 steps:
1) Add an overload to _Moveable while sets _M_type to 1.
2) Add a new constructor which takes _Moveable<T> t, performs default construction then does this->swap(t)
3) Add a new operator= which takes _Moveable<T> t and performs this->swap(t);


Changing the existing code consists of two main parts:
1) (obvious) adding __move around objects which can be moved
2) lots of function call things like copy_backward, or copy_and_allocate. Introduce new functions called move_backward and move_and_allocate which do the same thing, but using __move where possible.


Note that this does not deal with the issue of temporaries, particularily those generated when calling functions. Dealing with such things a) generally and b) without damaging the speed of simple types (like int, char, etc) appears like it would be very difficult. There are quite a few places in the standard library where such temporaries can actually be removed or reduced in number by being careful.

For example, std::sort introduces temporaries in 2 places. Firstly when partioning it creates a temporary which is the result of median(begin,end,begin+(end-begin)/2), and when calling __unguarded_insert. Both of these can be avoided without damaging complexity with careful coding (in median's case, copy the value into a temporary before calling the function, then pass by reference. In __unguarded_insert's case, inline the function as it is only used once).

I have already tried adding move symantics to vector and list and a few algorithms. It seems as if it will work quite well and the improvements in performance are (unsuprisingly) quite impressive. However this would also be quite a large scale change to almost every file, and so I'd perfer a few people say they are happy with the idea, and exactly how would be the best way to progress before beginning any serious coding.

Chris


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]