Подтвердить что ты не робот

С++ 11: написать конструктор перемещения с атомарным членом <bool>?

У меня есть класс с атомной переменной-членом:

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

Как следует перемещать конструктор?

Gcc 4.7 не нравится ни одна из моих попыток (например, добавление std::move() вокруг other.bar), и сеть здесь удивительно спокойна...

4b9b3361

Ответ 1

Поскольку вы перемещаетесь other, никто другой не получит к нему доступа. Таким образом, чтение из bar безопасно, пусть оно атомарно или нет.

atomic<T> имеет только два конструктора, один из которых по умолчанию - (), а другой - (T). Таким образом, ваш код выглядит так, как будто он должен компилироваться. Если это не так, что произойдет, если вы static_cast other.bar до T, применяя конструктор (T), который будет использоваться?

: bar( static_cast< bool >( other.bar ) )

или который равен, а может быть, и менее уродливому:

: bar( other.bar.load( ) )

Ответ 2

std::atomic не может быть скопирован или перемещен, потому что его конструктор копирования удален, и конструктор перемещения не определен. Вы должны явно загрузить другое значение и использовать его для создания нового значения, как было указано в ответе gustaf.

Почему std::atomic не движется? Поскольку это примитив синхронизации, все потоки должны синхронизироваться с одними и теми же данными (то есть с тем же адресом). Когда вы копируете (или перемещаете) атомное значение, вы должны использовать какой-то протокол связи. Это может быть просто, как в вашем примере (просто загрузите его и используйте для инициализации нового атома), но, в общем, я считаю, что это хорошее дизайнерское решение от С++ 11, чтобы заставить вас подумать об этом. В противном случае это может привести к тому, что код выглядит нормально, но имеет некоторые проблемы с синхронизацией.

Ответ 3

Создание шаблона atomic<bool> по существу выглядит следующим образом:

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

Итак, когда вы пытаетесь его скопировать:

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

Выбран удаленный экземпляр копии и вызывает ошибку компиляции.

Вам нужно явно передать bool, чтобы пройти через operator bool() --> atomic<bool>(bool)...

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