Inicialización del vector de atómica.

12

Considerar:

void foo() {
  std::vector<std::atomic<int>> foo(10);
  ...
}

¿Son válidos los contenidos de foo ahora? ¿O necesito recorrerlos e inicializarlos explícitamente? He comprobado Godbolt y parece estar bien, sin embargo, el estándar parece estar muy confundido en este punto.

El constructor std :: vector dice que inserta instancias insertadas por defecto de std::atomic<int>, que son valores inicializados a través de la colocación new.

Creo que se aplica este efecto de inicialización de valor:

2) si T es un tipo de clase con un constructor predeterminado que no es ni proporcionado por el usuario ni eliminado (es decir, puede ser una clase con un constructor predeterminado implícitamente definido o predeterminado), el objeto está inicializado en cero y luego es default-initialized si tiene un constructor predeterminado no trivial;

Entonces me parece que los atómicos están inicializados en cero. Entonces la pregunta es, ¿la inicialización cero de un std::atomic<int>resultado en un objeto válido?

¿Voy a adivinar que la respuesta es "sí en la práctica pero no está realmente definida"?

Nota: Esta respuesta concuerda en que está inicializada en cero, pero en realidad no dice si eso significa que el objeto es válido.

Timmmm
fuente

Respuestas:

7

Tienes razón al preocuparte. De acuerdo con los estándares atómica tiene el constructor por defecto llamada, sin embargo han no han inicializado como tal. Esto se debe a que el constructor predeterminado no inicializa el atómico:

La inicialización predeterminada std::atomic<T>no contiene un Tobjeto, y sus únicos usos válidos son la destrucción e inicialización por std :: atomic_init

Esto es algo en violación de las reglas del lenguaje normal, y algunas implementaciones se inicializan de todos modos (como ha notado).

Dicho esto, recomendaría dar un paso adicional para asegurarse al 100% de que se inicializan correctamente de acuerdo con el estándar; después de todo, se trata de concurrencia donde los errores pueden ser extremadamente difíciles de rastrear.

Hay muchas formas de esquivar el problema, incluido el uso de wrapper:

struct int_atomic {
   std::atomic<int> atomic_{0};//use 'initializing' constructor
};
Darune
fuente
O realmente usar atomic_init. De todos modos
carreras de ligereza en órbita el
El constructor predeterminado es trivial, por lo que no se llama de todos modos (según la cita en la pregunta)
Lightness Races in Orbit
@LightnessRaceswithMonica que también es posible, solo quería resaltar el contenedor
darune el
@LightnessRaceswithMonica esta es una excepción a las reglas del lenguaje normal, aunque algunos compiladores no implementan esta excepción. No estoy seguro de que la respuesta de StoreTeller sea 100% precisa.
Darune
2

Incluso si se llamara al constructor predeterminado (no lo es, porque es trivial), en realidad no hace nada .

Obviamente, no se puede garantizar que la inicialización cero produzca un valor atómico válido; esto solo funcionará si por casualidad se crea un atómico válido inicializando a cero todos sus miembros.

Y, dado que los atómicos no son copiables, no puede proporcionar un valor de inicialización en el constructor de vectores.

Ahora debe recorrer el contenedor y std::atomic_initcada elemento. Si necesita bloquear esto, está bien porque ya está sincronizando la creación del vector por la misma razón.

Carreras de ligereza en órbita
fuente
@darune, considero que es una especie de sincronización;)
ligereza corre en órbita el