I've got a class with an atomic member variable:
struct Foo { std::atomic<bool> bar; /* ... lots of other stuff, not relevant here ... */ Foo() : bar( false ) {} /* Trivial implementation fails in gcc 4.7 with: * error: use of deleted function ‘std::atomic<bool>::atomic(const td::atomic<bool>&)’ */ Foo( Foo&& other ) : bar( other.bar ) {} }; Foo f; Foo f2(std::move(f)); // use the move
How should be move constructor look like?
Gcc 4.7 doesn't like any of my attempts (like adding std::move()
around the other.bar
) and the net is surprisingly quiet here...
std::atomic is neither copyable nor movable.
You need atomic<bool> to avoid race-conditions. A race-condition occurs if two threads access the same memory location, and at least one of them is a write operation. If your program contains race-conditions, the behavior is undefined.
Move Constructor And Semantics: std::move() is a function used to convert an lvalue reference into the rvalue reference. Used to move the resources from a source object i.e. for efficient transfer of resources from one object to another.
std::atomic
is not copyable or movable because its copy constructor is deleted and no move constructor is defined. You have to explicitly load the other value and use it construct the new value, as it was pointed out in gustaf's answer.
Why is std::atomic
not movable? As it is a synchronization primitive, all threads have to synchronize on the same data (i.e., the same address). When you copy (or move) an atomic value, you have to use some communication protocol. It may be simple, as in your example (just load it and use it to initialize the new atomic) but, in general, I think it is a good design decision by C++11 to force you to think about it. Otherwise, it may result in code that looks fine, but has some subtile synchronization issues.
Since you're moving other
, no one else will access it. So reading from its bar
is safe, wether it's atomic or not.
atomic<T>
only has two constructors, one being the default ()
, the other being (T)
. So, your code looks like it should compile. If it doesn't, what happens if you static_cast other.bar
to T
, enforcing the (T)
constructor to be used?
: bar( static_cast< bool >( other.bar ) )
or which is equal to, and perhaps less ugly:
: bar( other.bar.load( ) )
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With