Initialisierung des Vektors der Atomik

12

Erwägen:

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

Sind die Inhalte von foo jetzt gültig? Oder muss ich sie explizit durchlaufen und initialisieren? Ich habe Godbolt überprüft und es scheint in Ordnung zu sein, jedoch scheint der Standard in diesem Punkt sehr verwirrt zu sein.

Der Konstruktor std :: vector gibt an, dass standardmäßig eingefügte Instanzen von eingefügt werden std::atomic<int>, deren Wert über die Platzierung initialisiert wird new.

Ich denke, dieser Effekt der Wertinitialisierung gilt:

2) Wenn T ein Klassentyp mit einem Standardkonstruktor ist, der weder vom Benutzer bereitgestellt noch gelöscht wird (dh es kann sich um eine Klasse mit einem implizit definierten oder standardmäßigen Standardkonstruktor handeln), wird das Objekt mit Null initialisiert und ist es dann Standardinitialisiert, wenn es einen nicht trivialen Standardkonstruktor hat;

Es scheint mir also, dass die Atomics auf Null initialisiert sind. Die Frage ist also, ob die Nullinitialisierung eines std::atomic<int>Ergebnisses zu einem gültigen Objekt führt.

Ich werde vermuten, dass die Antwort "Ja in der Praxis, aber es ist nicht wirklich definiert" ist?

Hinweis: Diese Antwort stimmt zu, dass sie mit Null initialisiert ist, sagt jedoch nicht wirklich aus, ob dies bedeutet, dass das Objekt gültig ist.

Timmmm
quelle

Antworten:

7

Sie haben Recht, besorgt zu sein. Standardmäßig hat die Atomics den Standardkonstruktor aufgerufen, sie wurden jedoch nicht als solche initialisiert. Dies liegt daran, dass der Standardkonstruktor das Atom nicht initialisiert:

Die Standardinitialisierung std::atomic<T>enthält kein TObjekt und wird nur durch Zerstörung und Initialisierung durch std :: atomic_init verwendet

Dies verstößt etwas gegen die normalen Sprachregeln, und einige Implementierungen werden trotzdem initialisiert (wie Sie bemerkt haben).

Abgesehen davon würde ich empfehlen, den zusätzlichen Schritt zu unternehmen, um 100% ig sicherzustellen, dass sie gemäß dem Standard korrekt initialisiert werden - schließlich haben Sie es mit Parallelität zu tun, bei der es äußerst schwierig sein kann, Fehler aufzuspüren.

Es gibt viele Möglichkeiten, dem Problem auszuweichen, einschließlich der Verwendung von Wrapper:

struct int_atomic {
   std::atomic<int> atomic_{0};//use 'initializing' constructor
};
Darune
quelle
Oder tatsächlich verwenden atomic_init. Sie müssen ohnehin schon um den Code in der Frage synchronisieren
Lightness Races in Orbit
Der Standardkonstruktor ist trivial, daher wird er sowieso nicht aufgerufen (gemäß dem Zitat in der Frage)
Lightness Races in Orbit
@ LightnessRaceswithMonica das ist auch möglich, ich wollte nur den Wrapper
hervorheben
@LightnessRaceswithMonica Dies ist eine Ausnahme von den normalen Sprachregeln - obwohl einige Compiler diese Ausnahme nicht implementieren. Ich bin mir nicht sicher, ob die StoreTeller-Antwort 100% korrekt ist.
Darune
2

Selbst wenn der Standardkonstruktor aufgerufen wurde (nicht, weil er trivial ist) , macht er eigentlich nichts .

Eine Nullinitialisierung kann offensichtlich nicht garantiert werden, um ein gültiges Atom zu erzeugen. Dies funktioniert nur, wenn zufällig ein gültiges Atom durch Nullinitialisierung aller seiner Mitglieder erstellt wird.

Und da Atomics nicht kopierbar sind, können Sie im Vektorkonstruktor keinen Initialisierungswert angeben.

Sie sollten jetzt den Container und std::atomic_initjedes Element durchlaufen. Wenn Sie dies umgehen müssen, ist dies in Ordnung, da Sie die Erstellung des Vektors aus demselben Grund bereits synchronisieren.

Leichtigkeitsrennen im Orbit
quelle
@ Darune Ich halte das für eine Art Synchronisation;)
Leichtigkeitsrennen im Orbit