Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11: write move constructor with atomic<bool> member?

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...

like image 764
Chris Avatar asked Jan 06 '13 12:01

Chris


People also ask

Can std :: atomic be moved?

std::atomic is neither copyable nor movable.

Does bool need to be atomic?

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.

What does move () do in C ++?

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.


2 Answers

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.

like image 138
Philipp Claßen Avatar answered Oct 05 '22 09:10

Philipp Claßen


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( ) )

like image 24
gustaf r Avatar answered Oct 05 '22 10:10

gustaf r