2016-07-04 8 views
-2

Ich versuche zu verstehen, wenn Compiler Array initialisieren sollten und wann sie es initialisieren sollten. Ich versuche, zwei Möglichkeiten: eine rohe Array, ein weiteres Array in einer Struktur zusammengefasst:Warum Compiler Nullen in Arrays setzen, während sie nicht müssen?

const int N = 1000; 

struct A 
{ 
    uint32_t arr[N]; 

    A() = default; 
}; 

void print(uint32_t* arr, const std::string& message) 
{ 
    std::cout << message << ": " << 
    (std::count(arr, arr + N, 0) == N ? "all zeros" : "garbage") << std::endl; 
} 

int main() 
{ 
    uint32_t arrDefault[N]; 
    print(arrDefault, "Automatic array, default initialization"); 

    uint32_t arrValue[N] = {}; 
    print(arrValue, "Automatic array, value initialization"); 

    uint32_t* parrDefault = new uint32_t[N]; 
    print(parrDefault, " Dynamic array, default initialization"); 

    uint32_t* parrValue = new uint32_t[N](); 
    print(parrValue, " Dynamic array, value initialization"); 

    A structDefault; 
    print(structDefault.arr, "Automatic struct, default initialization"); 

    A structValue{}; 
    print(structValue.arr, "Automatic struct, value initialization"); 

    A* pstructDefault = new A; 
    print(pstructDefault->arr, " Dynamic struct, default initialization"); 

    A* psstructValue = new A(); 
    print(psstructValue->arr, " Dynamic struct, value initialization"); 
} 

Hier ist, was ich sehe für clang und VC++:

Automatic array, default initialization: garbage 
Automatic array, value initialization: all zeros 
    Dynamic array, default initialization: garbage 
    Dynamic array, value initialization: all zeros 
Automatic struct, default initialization: all zeros 
Automatic struct, value initialization: all zeros 
    Dynamic struct, default initialization: garbage 
    Dynamic struct, value initialization: all zeros 

Ausgang für gcc unterschiedlich ist nur in der erste Zeile, wo es auch "alle Nullen" setzt.

Aus meiner Sicht sind sie alle falsch, und was ich erwarten ist:

Automatic array, default initialization: garbage 
Automatic array, value initialization: all zeros 
    Dynamic array, default initialization: garbage 
    Dynamic array, value initialization: all zeros 
Automatic struct, default initialization: garbage 
Automatic struct, value initialization: garbage 
    Dynamic struct, default initialization: garbage 
    Dynamic struct, value initialization: garbage 

D.h. Ausgabe ist ok für rohe Arrays (außer gcc): wir haben Müll für Standard und Nullen für Wert. Groß. Aber für eine Struktur würde ich erwarten, ständig Müll zu haben. Von default initialization:

Standard Initialisierung wird in drei Situationen durchgeführt:

  1. ...
  2. ...
  3. wenn eine Basisklasse oder ein nicht-statisches Datenelement wird nicht erwähnt in eine Konstruktorinitialisierungsliste und dieser Konstruktor wird aufgerufen.

Die Wirkungen von Standardinitialisierung sind:

  • wenn T ein nicht-POD (bis C++ 11) Klasse-Typ, ...
  • wenn T ein Array-Typ ist, jedes Element des Arrays ist default-initialisiert;
  • Andernfalls wird nichts unternommen: Die Objekte mit automatischer Speicherdauer (und deren Unterobjekte) werden initialisiert, um die Werte zu bestimmen.

In meinem Beispiel I nicht-statisches Datenelement, das nicht in einem Konstruktor Initialisiererliste erwähnt wird, die ein Array von POD-Typ ist. Ich erwarte, dass es mit unbestimmten Werten belassen wird, egal wie meine Struktur aufgebaut ist.

Meine Fragen sind:

  • Warum Compiler, dass verletzen? Ich meine, warum setzen sie Nullen, wenn sie nicht müssen, verschwenden meine Laufzeit? Liege ich falsch in meinen Lesungen?
  • Wie kann ich ein solches Verhalten erzwingen, um sicherzustellen, dass ich meine Runtime-Popup-Arrays nicht mit Nullen verschwenden?
  • Warum Gcc Wert Initialisierung für ein automatisches Array führt?
+0

Warum Compiler * was * verletzen? Ich sehe keine Verstöße gegen den Standard in Ihrem Code. Auf der anderen Seite gibt es so viel davon, dass ich etwas übersehen habe. – juanchopanza

+0

Wenn der Wert unbestimmt ist, darf der Compiler * * keine Nullen schreiben? –

+0

@TheodorosChatzigiannakis Es ist erlaubt, aber Compiler versuchen, sehr optimierten Code zu produzieren. Warum sollten sie Nullen setzen, während sie das nicht dürfen? Der einzige mögliche Grund, wenn sie _have_ haben. – Mikhail

Antwort

5

A structValue{}; ist Aggregat-Initialisierung, also 0 sind garantiert.

Da A keinen vom Benutzer bereitgestellten Konstruktor hat, weil explizit vordefinierte Konstruktoren nicht als solche gezählt werden, gilt das Gleiche für die Initialisierung des Werts wie in A* psstructValue = new A();.

Für die Standardinitialisierungsfälle: Das Lesen nicht initialisierter Variablen ist UB und das Verhalten Undefined ist nicht definiert. Der Compiler kann damit machen, was er will. Das Anzeigen von 0 ist genauso legal wie ein Absturz. Vielleicht gab es sogar 0 in der Erinnerung, die du zufällig liest. Vielleicht fühlten sich die Compiler wie 0 initialisiert. Aus der Sicht des Standards ist beides gleich gut.

Das heißt, Sie haben eine bessere Chance, Müll zu sehen, wenn Sie mit Release/optimierten Builds testen. Debugbuilds neigen dazu, zusätzliche Dinge zu tun, um die Diagnose von Problemen zu erleichtern, einschließlich einer zusätzlichen Initialisierung.

(Für den Rekord: gcc und klingeln mit -O3 scheinen keine unnötige Initialisierung auf meinem Linux-System auf den ersten Blick. Trotzdem habe ich "alle Nullen" für jeden Fall. Das scheint zufällig.)

+0

Netter Haken über Aggregat-Initialisierung. Im Übrigen glaube ich nicht, dass diese Programme nur drucken, was sie wollen, wegen UB. Alle Fälle zeigen UB, aber einige haben Müll und andere nicht. Ich glaube, das liegt daran, dass sie ehrlich in die richtigen Orte in der Erinnerung schauen. – Mikhail

+1

@Michail Wie gesagt, UB ist undefiniert. Der Initialisierer des Compilers ist völlig in Ordnung, da Sie rechtlich keinen Unterschied feststellen können. –

+0

Also was denkst du, setzt Compiler Nullen da oder nicht? Ich verstehe, dass es erlaubt ist, dies zu tun und zu verstehen, dass ich es direkt nur durch Erinnerungsdumps und Disasm beobachten kann, aber trotzdem, was ist dein Anspruch? – Mikhail

0

Die andere Antwort adressiert nicht wirklich die REASON nur irgendwie tanzt mit der Sprachspezifikation herum.

Der eigentliche Grund liegt daran, wie der Initialisierungsprozess funktioniert.

Stellen Sie sich die Frage, woher ich weiß, wenn etwas initialisiert wird.

Deshalb müssen statische Daten initialisiert werden, während Daten, die nicht sind, nicht. Wenn Sie nicht zuerst alle statischen Daten durchgehen und auf Null setzen, wäre der statische dynamische Initialisierungsprozess (nachschlagen) grundsätzlich unmöglich.

Sie würden ständig auf Probleme wie zwei Statiken stoßen, die sich bei der Initialisierung schräg aufeinander beziehen und alles auseinander fällt.

Also ohne diese Regel C++ im Grunde ist es unmöglich, einen Compiler für zu schreiben. Obwohl es andere Initialisierungsschemata gibt, die diese Anforderung nicht haben, würde es eine große Überarbeitung der Sprache erfordern, um sie zu implementieren.

+1

Was ist Ihre Antwort? – Mikhail

Verwandte Themen