tags:

views:

275

answers:

3

Since we have rvalue references in C++0x it seems to me that it should be possible to implement std::swap as an atomic operation with CAS. Is this the case in the new standard, and if not why?

+6  A: 

It is not atomic. Atomic operations are not cheap and 99% of the time you do not need the atomicity. There are (IIRC) some other means to get atomic operations but std::swap() is not one of them.

wilx
Would it be possible to implement an std::atomic_swap for any type in C++0x? If soo, how?
ronag
@ronag - the simplest way would be a global mutex on the swap operation. ;-)
Omnifarious
@Omnifarious: good answer, but not what I had expected. :)
ronag
@ronag: I agree with Omnifarious. In fact, I think that that is pretty much the only viable option.
wilx
@ronag: some platforms will be able to provide lock-free swapping for some types (up to a certain size). This should all be handled by a decent implementation of `std::atomic_exchange`, and you can check whether this uses a lock using `std::atomic<T>::is_lock_free()`.
Mike Seymour
+5  A: 

Simple answer no, not really.

While you can use CAS to implement atomic operations, in most cases you would have to redesign part of the implementation to do so, and you will, in most cases, have an impact in performance in all usages.

Consider a current implementation of a vector in g++. It keeps three pointers: begin, end, end_of_capacity. How would you make swap atomic for such a vector? You could simplify things by pushing all three pointers into a dynamically allocated block of memory, and then implementing an atomic swap would be simpler, just swap the pointers. The problem is that you have added an extra memory allocation to the container and an extra dereference operation in each and every access through the container (iterators would perform similar to the original implementation).

Do read at this answer by FredOverflow for a simple explanation on move semantics.

David Rodríguez - dribeas
You forget that with rvalue references and std::move it just swaps the memory address. I might be wrong.
ronag
Had it only swapped memory addresses, we wouldn't have to define Move Constructor for complex types. As far as I imagine, it may only swap memory addresses when dealing with temporary POD declared on the stack in a fonction needing to return that precise POD type.But in other cases, it calls the Move constructor. Well... I think so.
Stephane Rolland
@ronag: You're wrong. How does one swap memory addresses? At some point (namely, with primitives), moving has to be the same as copying. And that is the case.
GMan
Thank you for clearing that up, seems I have misunderstood how rvalues work. I will have to study this a bit more in-depth.
ronag
@ronag: [shameless plug](http://stackoverflow.com/questions/3106110/can-someone-please-explain-move-semantics-to-me/3109981#3109981)
FredOverflow
@FredOverflow: No need to shame on you, that is a nice answer, well related and deserves any upvote it might get! I am adding the link to the answer so that you do not need any more shame.
David Rodríguez - dribeas
A: 

Not every class can have a move assignment operator which can be implemented more efficiently than the regular assignment operator. Case in point std::array which has a native array as a member. Another case is a std::string where the small string optimization is used (for small strings).

Therefore generally you can't say anything about std::swap with move semantics that you couldn't say about std::swap in C++98. For some cases it will be better but not for the general case.

Motti