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.

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
};

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.


@darune, considero que es una especie de sincronización;)
— ligereza corre en órbita el
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.