2016-03-31 12 views
5

Was bedeutet 0-Initialisierung von std::atomic<integral_type> Variable bedeuten?Ist die 0-Initialisierung von Atomics garantiert, um den Wert member auf 0 zu setzen?

Ursprünge der Frage. Ich habe eine Funktion-statische von std::atomic<std::int>, die ich vor der ersten Verwendung auf 0 gesetzt werden soll (versteht sich von selbst, Funktion, wo das Array befindet sich in unvorhersehbarer Weise aus mehreren Threads aufgerufen).

Dieses Stück Code ist gut aussehend, aber nicht beschränkt auf atomics Kompilieren durch sein Nicht-Kopie konstruierbar:

#include <array> 
#include <atomic> 

void foo() { 
    using t = std::atomic<int>; 
    static std::array<t, 2> arr = {0, 0}; // <-- explicit, but errors out (see below) 
    static std::array<t, 2> arr2; // <-- implicit?, works 
} 

error: use of deleted function ‘std::atomic::atomic(const std::atomic&)’ std::array arr = {0, 0};

Jetzt verstehe ich, dass statische std::array zu geht 0-initialisieren alle es ist Mitglieder und std::atomic<> wird 0-initialisiert. Aber haben wir eine explizite oder implizite Garantie, dass alle Werte auf 0 gesetzt werden? Der gesunde Menschenverstand sagt "Ja" - schließlich nehmen wir an, dass die Klasse ein Mitglied vom Typ int haben wird, und dieses Mitglied wird 0-initialisiert. Aber basiert diese Annahme auf soliden Standardgrundlagen?

+0

Interessant. Dies erzeugt den Fehler in [GCC] (http://coliru.stacked-crooked.com/a/467922a19099c9a7) und [Clang] (http://coliru.stacked-crooked.com/a/3c8e5cba2847b829), aber nicht mit MSVC++. Ein Nebeneffekt von [Kopie Elision] (http://en.cppreference.com/w/cpp/language/copy_elision)? – wally

+1

@flatmouse MSVC ist fehlerhaft, wie wir alle wissen :) – SergeyA

+0

Ich denke du meinst voll von zusätzlichen und undokumentierten "Funktionen" :) – wally

Antwort

4

Verwendung (in der Regel redundant) Zahnspange copy-Initialisierung zu vermeiden:

static t arr[2] = {{0}, {0}}; 
static std::array<t, 2> arr2 = {{{0}, {0}}}; /* Need extra pair here; otherwise {0} is 
               treated as the initializer of the internal 
               array */ 

Demo. Wenn wir die geschweiften Klammern weglassen, wird eine Kopie initialisiert, was ein temporäres Erstellen und Kopieren erfordert. Mit den geschweiften Klammern haben wir die copy-list-Initialisierung, die genauso funktioniert wie die direkte list-Initialisierung (d. H. Initialisiert jedes Element mit {0}, was in Ordnung ist).

Sie können auch warten, bis guaranteed copy elision eingeführt wird und verwenden Sie einfach Ihre Syntax.

+0

Ja, ich könnte call_once tun, aber es gibt keine Schönheit darin. Ich würde gerne meine Syntax garantiert werden :) – SergeyA

+0

@SergeyA Ihre Syntax ist, wie es aussieht, schlecht gebildet. Es wird einige Zeit vergehen, bis der Vorschlag, mit dem ich mich verbinde, inkorporiert wird. – Columbo

+0

Nun, worauf basiert diese Aussage? Dieser 0-initialisierende Atom wird nicht 0-initialisiert mein Mitglied? Ich bin immer noch Upvoting für garantierte Kopie elision Stück, und wenn nichts besser herauskommt, werde ich für das gleiche akzeptieren. – SergeyA

0

Von cppreference, Dokumentation des Standardkonstruktors von std :: Atom sagt:

Constructs new atomic variable.

1) The default constructor is trivial: no initialization takes place other than zero initialization of static and thread-local objects. std::atomic_init may be used to complete initialization.

So werden Sie Initialisierung Schleife sicher Columbo benötigen.

+0

Nun, es gibt eine 0-Initialisierung, die stattfindet, weil das Array statisch ist. Die Frage ist, was 0-Initialisierung für Werte innerhalb von Atomen bedeutet. – SergeyA

+0

@SergeyA 0-Initialisierung oder Standardinitialisierung? –

+0

0 Initialisierung in diesem Fall. 'statisch' macht das für dich. – SergeyA

0

Was Sie unterscheiden müssen, ist Standard-Initialisierung und Null-Initialisierung. Ich habe schon vor einiger Zeit über dieses Thema gesprochen und bin zu dem Schluss gekommen, dass der Standard implizit die atomische Klasse benötigt, um bei der Initialisierung identisch mit Strukturen zu agieren.

Der nicht atomare Basistyp muss trivial kopierbar sein, und der atomare Typ muss sowohl die Standardinitialisierung unterstützen als auch statisch mit (und ohne) ATOMIC_VAR_INIT initialisiert werden. Es gibt keine sauberen Lösungen, die ich mir vorstellen kann, die nicht mit einer inneren Struktur oder einer Struktur enden (ich habe eine atomare Implementierung für ein firmeninternes RT OS geschrieben).

So, wenn der Standard nicht erfordert, lenkt zumindest die Implementierung in Richtung einer Lösung, wo Null-Initialisierung genau das tut, was Sie wollen.

Ich habe eine Live Example die sich die folgende vergleicht:

std::array<t, 2> default; 
std::array<t, 2> zero{}; 
std::array<t, 2> explicit{{{0},{0}}}; 

Sie werden sehen, dass die Null-Initialisierung auf die explizite Version identisch ist, und mit gcc 6.3.0 noch effizienter.

Ich wiederhole nur, ich glaube nicht, dass der Standard explizit eine Null-Initialisierung erfordert, um sich so zu verhalten, aber - nach meinem Verständnis - gegeben, was definiert ist, muss es notwendigerweise.