
On 8/23/2011 11:35 AM, Julian Gonggrijp wrote:
Eric Niebler wrote:
On 8/23/2011 8:06 AM, Julian Gonggrijp wrote: <snip>
[...] template <class T> void move_raw (typename UNDERLYING_TYPE(T)& source, T& target) { target = source; }
Yikes, no. T's copy constructor can throw. This should be a move, and then only if T's move assign cannot throw. Otherwise, move_raw should probably be undefined.
If move_raw is implemented as a copy, it doesn't really matter if the copy throws because the source object is left in a valid state, right?
No. Imagine: UNDERLYING_TYPE(X) tmp1; UNDERLYING_TYPE(Y) tmp2; move_raw(x, tmp1); // 1 move_raw(y, tmp2); // 2 move_raw(tmp2, y); // 3 move_raw(tmp1, x); // 4 Imagine that X has a move_raw that leaves its source in an invalid state and that Y has a move_raw that can throw. Now also imagine line 2 throws. Oops.
I mean, with the copy-based swap we usually also don't worry about the possibility that one of the copies might throw...
Yes, we do. Read about noexcept.
You may decide to provide an easy way for users to opt-in for a memcpy based solution, but that option should only be available only on compilers for which memcpy-ing non-PODs is empirically known to work. And there should be a warning about the non-portability about doing that.
If you are right and using copy as a fallback for raw moves is not an option, it means a significant loss of generality.
Like I said, you need to solve the exception safety issues. Look into noexcept; there may be relief there. -- Eric Niebler BoostPro Computing http://www.boostpro.com