Inizializzazione del vettore di atomica


12

Prendere in considerazione:

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

I contenuti di foo sono ora validi? O devo ripetere esplicitamente e inizializzarli? Ho controllato Godbolt e sembra che vada bene, tuttavia lo standard sembra essere molto confuso su questo punto.

Il costruttore std :: vector afferma di inserire istanze di default inseritestd::atomic<int> , che sono valori inizializzati tramite posizionamento new.

Penso che si applichi questo effetto di inizializzazione del valore:

2) se T è un tipo di classe con un costruttore predefinito che non è né fornito dall'utente né eliminato (ovvero, può essere una classe con un costruttore predefinito implicitamente definito o predefinito), l'oggetto viene inizializzato con zero e quindi è default-inizializzato se ha un costruttore predefinito non banale;

Quindi mi sembra che gli atomici siano a zero inizializzati. Quindi la domanda è: l'inizializzazione zero di un std::atomic<int>risultato in un oggetto valido?

Ho intenzione di indovinare che la risposta è "sì, in pratica, ma non è davvero definita"?

Nota: questa risposta concorda sul fatto che è inizializzata a zero, ma in realtà non dice se ciò significa che l'oggetto è valido.

Risposte:


7

Hai ragione a essere preoccupato. Secondo la norma i Atomics ha il costruttore di default chiamato, tuttavia essi sono non stati inizializzati in quanto tale. Questo perché il costruttore predefinito non inizializza l'atomico:

L'inizializzazione predefinita std::atomic<T>non contiene un Toggetto e i suoi unici usi validi sono distruzione e inizializzazione di std :: atomic_init

Ciò è in qualche modo in violazione delle normali regole del linguaggio e alcune implementazioni si inizializzano comunque (come hai notato).

Detto questo, consiglierei di fare il possibile per assicurarti che siano inizializzati correttamente al 100% secondo gli standard, dopo tutto hai a che fare con la concorrenza in cui i bug possono essere estremamente difficili da rintracciare.

Esistono molti modi per evitare il problema, incluso l'uso di wrapper:

struct int_atomic {
   std::atomic<int> atomic_{0};//use 'initializing' constructor
};

O effettivamente usare atomic_init. Devi già sincronizzare il codice nella domanda comunque
Lightness Races in Orbit

Il costruttore predefinito è banale, quindi non viene chiamato comunque (per la citazione nella domanda)
Razze di luminosità in orbita

@LightnessRaceswithMonica che è anche possibile, volevo solo evidenziare il wrapper
darune

@LightnessRaceswithMonica questa è un'eccezione alle normali regole del linguaggio, anche se alcuni compilatori non implementano questa eccezione. Non sono sicuro che la risposta dello StoreTeller sia accurata al 100%.
martedì

2

Anche se il costruttore predefinito è stato chiamato (non lo è, perché è banale) in realtà non fa nulla .

L'inizializzazione zero ovviamente non può essere garantita per produrre un atomico valido; questo funzionerà solo se per caso viene creato un atomico valido inizializzando zero tutti i suoi membri.

Inoltre, poiché gli atomici non sono copiabili, non è possibile fornire un valore di inizializzazione nel costruttore del vettore.

Ora dovresti passare sopra il contenitore e std::atomic_initciascun elemento. Se hai bisogno di aggirare questo, va bene perché stai già sincronizzando la creazione del vettore per lo stesso motivo.


@darune Lo considero una sorta di sincronizzazione;)
Razze di leggerezza in orbita
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.