C++11: write move constructor with atomic member?


Tengo una clase con una variable miembro atómico:

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

¿Cómo debería ser el aspecto de move constructor?

A Gcc 4.7 no le gusta ninguno de mis intentos (como agregar std::move() alrededor de other.bar) y la red es sorprendentemente tranquila aquí...

Author: ildjarn, 2013-01-06

3 answers

Ya que te estás moviendo other, nadie más accederá a él. Así que leer de su bar es seguro, sea atómico o no.

atomic<T> solo tiene dos constructores, uno es el predeterminado (), el otro es (T). Por lo tanto, su código parece que debería compilar. Si no lo hace, ¿qué sucede si static_cast other.bar a T, haciendo cumplir el constructor (T) a ser utilizado?

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

O que es igual a, y quizás menos feo:

: bar( other.bar.load( ) )

 15
Author: gustaf r,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-06 13:05:54

std::atomic no se puede copiar ni mover porque su constructor de copia se elimina y no se define ningún constructor de movimiento. Tienes que cargar explícitamente el otro valor y usarlo para construir el nuevo valor, como se señaló en la respuesta de gustaf.

¿Por qué std::atomic no es móvil? Como es una sincronización primitiva, todos los subprocesos tienen que sincronizarse en los mismos datos (es decir, la misma dirección). Cuando copia (o mueve) un valor atómico, tiene que usar algún protocolo de comunicación. Puede ser simple, como en tu ejemplo (solo cárgalo y úsalo para inicializar el nuevo atómico) pero, en general, creo que es una buena decisión de diseño por parte de C++11 obligarte a pensar en ello. De lo contrario, puede resultar en código que se ve bien, pero tiene algunos problemas de sincronización sutiles.

 24
Author: Philipp Claßen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-06 14:21:03

La instanciación de plantilla de atomic<bool> esencialmente se ve así:

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

Así que cuando intentas copiarlo:

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

Se elige el constructor de copia eliminada y causa un error de compilación.

Necesitas hacer un cast explícito a bool para pasar por operator bool() --> atomic<bool>(bool)...

atomic<bool> a = ...;
atomic<bool> b(bool(a));
 1
Author: Andrew Tomazos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-06 15:46:23