webentwicklung-frage-antwort-db.com.de

Der Operator new initialisiert den Speicher auf Null

Es gibt einen solchen Code:

#include <iostream>

int main(){
  unsigned int* wsk2 = new unsigned int(5);
  std::cout << "wsk2: " << wsk2 << " " << *wsk2 << std::endl;
  delete wsk2;
  wsk2 = new unsigned int;
  std::cout << "wsk2: " << wsk2 << " " << *wsk2 << std::endl;
  return 0;
}

Ergebnis:

wsk2: 0x928e008 5
wsk2: 0x928e008 0

Ich habe gelesen, dass new den Speicher nicht mit Nullen initialisiert. Aber hier scheint es so zu sein. Wie funktioniert es?

65
scdmb

Es gibt zwei Versionen:

wsk = new unsigned int;      // default initialized (ie nothing happens)
wsk = new unsigned int();    // zero    initialized (ie set to 0)

Funktioniert auch für Arrays:

wsa = new unsigned int[5];   // default initialized (ie nothing happens)
wsa = new unsigned int[5](); // zero    initialized (ie all elements set to 0)

Als Antwort auf Kommentar unten.

Ehm ... bist du sicher, dass new unsigned int[5]() die ganzen Zahlen auf Null setzt?

Anscheinend ja:

[C++ 11: 5.3.4/15]: Ein neuer Ausdruck, der ein Objekt vom Typ T erstellt, initialisiert dieses Objekt wie folgt: Wenn der Neuinitialisierer weggelassen wird, wird das Objekt standardmäßig initialisiert (8.5). Wird keine Initialisierung durchgeführt, hat das Objekt einen unbestimmten Wert. Andernfalls wird der Neuinitialisierer gemäß den Initialisierungsregeln von 8.5 für die Direktinitialisierung interpretiert.

#include <new>
#include <iostream>


int main()
{
    unsigned int   wsa[5] = {1,2,3,4,5};

    // Use placement new (to use a know piece of memory).
    // In the way described above.
    // 
    unsigned int*    wsp = new (wsa) unsigned int[5]();

    std::cout << wsa[0] << "\n";   // If these are zero then it worked as described.
    std::cout << wsa[1] << "\n";   // If they contain the numbers 1 - 5 then it failed.
    std::cout << wsa[2] << "\n";
    std::cout << wsa[3] << "\n";
    std::cout << wsa[4] << "\n";
}

Ergebnisse:

> g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-Apple-darwin13.2.0
Thread model: posix
> g++ t.cpp
> ./a.out
0
0
0
0
0
>
161
Martin York

Es ist nicht garantiert, dass operator new Den Speicher für irgendetwas initialisiert, und der neuer Ausdruck, der einen unsigned int Ohne neuer Initialisierer zuweist, verlässt den Objekt mit einem unbestimmten Wert.

Das Lesen des Werts eines nicht initialisierten Objekts führt zu ndefiniertes Verhalten. ndefiniertes Verhalten Umfasst das Auswerten auf den Wert Null ohne negative Auswirkungen, kann jedoch dazu führen, dass etwas passiert, sodass Sie vermeiden sollten, dass es verursacht wird.

In C++ 11 wird die Sprache verwendet, in der die zugewiesenen Objekte default-initialized lauten, was bedeutet, dass bei Nicht-Klassentypen keine Initialisierung durchgeführt wird. Dies unterscheidet sich von der Bedeutung von default-initialized in C++ 03.

19
CB Bailey

Bei einigen Compilern initialisiert die Debug-Version von new die Daten, aber Sie können sich auf nichts verlassen.

Es ist auch möglich, dass der Speicher gerade 0 von einer vorherigen Verwendung hatte. Gehen Sie nicht davon aus, dass zwischen delete und new nichts mit dem Speicher passiert ist. Es könnte etwas im Hintergrund geschehen, das Sie nie bemerkt haben. Außerdem ist derselbe Zeigerwert möglicherweise nicht derselbe physische Speicher. Speicherseiten werden verschoben und ausgelagert. Ein Zeiger wird möglicherweise auf eine ganz andere Position als zuvor abgebildet.

Fazit: Wenn Sie einen Speicherort nicht speziell initialisiert haben, können Sie nichts über dessen Inhalt annehmen. Der Speichermanager weist möglicherweise nicht einmal einen bestimmten physischen Speicherort zu, bis Sie den Speicher verwenden.

Moderne Speicherverwaltung ist erstaunlich komplex, aber als C++ - Programmierer ist es Ihnen eigentlich egal (meistens ‡). Halten Sie sich an die Regeln und Sie werden keinen Ärger bekommen.

‡ Es könnte Sie interessieren, ob Sie optimieren, um Seitenfehler zu reduzieren.

4
Michael J

Das ist nicht operator new, das ist der Operator new. Es gibt tatsächlich einen großen Unterschied! Der Unterschied ist, dass operator new ist eine Funktion, die unformatierten Speicher zurückgibt. Wenn Sie den Operator new verwenden, wird ein Konstruktor für Sie aufgerufen. Es ist der Konstruktor, der den Wert dieses int festlegt, nicht operator new.