C++11: write move constructor with atomic me

2019-03-11 21:54发布

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

3条回答
成全新的幸福
2楼-- · 2019-03-11 22:18

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.

查看更多
forever°为你锁心
3楼-- · 2019-03-11 22:28

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

查看更多
Emotional °昔
4楼-- · 2019-03-11 22:40

The template instantiation of atomic<bool> essentially looks like this:

struct atomic<bool>
{
    atomic<bool>(bool);
    atomic<bool>( const atomic<bool>& ) = delete;
    operator bool() const;
}

So when you try to copy it:

atomic<bool> a = ...;
atomic<bool> b(a);

The deleted copy constructor is chosen and causes a compile error.

You need to explicitly cast to bool to go through operator bool() --> atomic<bool>(bool)...

atomic<bool> a = ...;
atomic<bool> b(bool(a));
查看更多
登录 后发表回答