Frage

Wie jeder weiß, der Visual C ++ Laufzeit markiert nicht initialisierte oder nur befreit Speicherblocks mit speziellem nicht-Null-Marker. Gibt es eine Möglichkeit, dieses Verhalten vollständig zu deaktivieren, ohne manuell alle nicht initialisierten Speicher Nullen einstellen? Es verursacht Chaos mit meinen gültig nicht null Kontrollen, da 0xFEEEFEEE != 0.

Hrm, vielleicht sollte ich ein bisschen besser erklären. Ich erstellen und initialisieren eine Variable (über neu), und das geht alles gut. Als ich es frei (über delete), setzt er den Zeiger statt 0xFEEEFEEE NULL. Wenn ich legen Sie eine richtige Prüfung für NULL, wie alle guten Programme, die ihre eigenen Speicher verwalten sollte, habe ich mit Problemen kommen, wie 0xFEEEFEEE eine NULL Prüfung ohne Probleme passiert. Gibt es eine gute Möglichkeit, andere als manuell alle Zeiger Einstellung NULL, wenn sie zu löschen, zu erkennen, wenn der Speicher bereits freigegeben worden ist? Ich würde es vorziehen, nicht Steigern Sie einfach, weil ich will nicht den Overhead , klein, es kann jedoch sein, denn das ist das einzige, was ich würde Schub für werden.

War es hilfreich?

Lösung

Es ist nicht die Aufgabe von delete alle Zeiger auf das Objekt NULL zurückgesetzt werden. Auch sollten Sie nicht die Standard-Speicherfüllen für die Fenster DEBUG Laufzeit ändern, und Sie sollten etwas, was wie boost::shared_ptr<> für Zeiger jede mögliche Weise verwenden.

Das heißt, wenn Sie wirklich wollen Ihr selbst in den Fuß schießen Sie können.

Sie können ändern default fill für die Fenster DEBUG Laufzeit durch einen allocator Haken wie folgt aus. Dies wird nur auf Speicher zugeordnet Objekt arbeiten!

int main(int argc,char** arv)
{
  // Call first to register hook    
  _CrtSetAllocHook(&zero_fill);
  // Do other stuff
  malloc(100);
}


int zero_fill(int nAllocType, 
              void* pvData, 
              size_t nSize,
              int nBlockUse, 
              long lRequest, 
              const unsigned char *szFileName, 
              int nLine )
{
  /// Very Importaint !! 
  /// infinite recursion if this is removed !!
  /// _CRT_BLOCK must not do any thing but return TRUE
  /// even calling printf in the _CRT_BLOCK will cause
  /// infinite recursion
  if ( nBlockUse == _CRT_BLOCK )
    return( TRUE );
  switch(nAllocType)
  {
  case _HOOK_ALLOC:
  case _HOOK_REALLOC:
    // zero initialize the allocated space.
    memset(pvData,0,nSize);
    break;
  case _HOOK_FREE:
    break;
  }
  return TRUE;
}

Andere Tipps

Wenn Sie einen Zeiger erstellen, initialisieren es explizit NULL. Ebenfalls nach einer delete. Je nach dem Wert von nicht initialisierten Daten (außer in einigen besonderen Fällen) bittet um Ärger.

Sie können sparen Sie sich eine Menge Kopfschmerzen durch eine Smart-Pointer-Klasse (zB boost::shared_ptr ), die mit automatisch befassen wird, ob ein Zeiger initialisiert wird oder nicht.

VC ++ 's Verhalten sollte nicht verursachen Chaos mit jedem gültig überprüfen Sie tun können. Wenn Sie die 0xfeeefeee sehen, dann haben Sie nicht in den Speicher geschrieben (oder haben sie befreit), so sollten Sie nicht aus dem Speicher liest sowieso.

Wenn Sie nicht initialisierten Speicher lesen, Ihre Schecks sind ganz sicher nicht „gültig“. Der Speicher wird freigegeben. Es könnte schon für etwas anderes im Einsatz sein. Sie können keine Annahmen über den Inhalt des nicht initialisierten Speicher in C / C ++ machen.

Java (und C #, glaube ich) wird gewährleistet, dass zugewiesene Speicher vor dem Gebrauch auf Null gesetzt wird, und natürlich die Garbage Collection verhindert, dass Sie freigegebene Speicher zu sehen, überhaupt nicht. Aber das ist nicht eine Eigenschaft des C-Heap, die direkt die Speicher freigibt.

Wenn Sie im Release-Modus anstelle von Debug-Modus zu bauen, wird die Laufzeit nicht auf nicht initialisierten Speicher füllt überhaupt, aber es wird immer noch nicht Nullen sein. Allerdings sollten Sie nicht auf dieses Verhalten abhängen - Sie sollten entweder explizit den Speicher selbst mit memset initialisieren (), Zeromemory () oder SecureZeroMemory () oder irgendwo ein Flag gesetzt, das anzeigt, dass der Speicher nicht ist noch initialisiert. nicht initialisierten Speicher zu lesen in undefinierten Verhalten führen.

Sie sagen:

  

Ich erstelle und eine Variable (über neu) initialisiert werden, und das geht alles gut. Als ich es frei (über delete), setzt er den Zeiger auf 0xFEEEFEEE statt NULL. Wenn ich eine richtige Prüfung für NULL einzufügen, wie alle guten Programme, die ihre eigenen Speicher verwalten sollte, habe ich mit Problemen kommen als 0xFEEEFEEE eine NULL Prüfung ohne Probleme passiert.

Auch die Debug-Heap-Routinen von MSVC den Wert der nicht ändern Zeiger Sie löschen - den Wert des Zeigers sind Löschen Sie nicht (auch auf NULL) ändern. Es klingt wie Sie einen Zeiger sind zugreifen, die auf das Objekt gehört, die Sie gerade gelöscht haben, was ein Fehler ist, schlicht und einfach.

Ich bin mir ziemlich sicher, dass das, was Sie einfach verschleiern einen ungültigen Speicherzugriff zu tun versuchen. Sie sollen einen Code-Snippet schreiben, uns zu zeigen, was wirklich geschieht.

@ Jeff Hubbard ( Kommentar ):

  

Das tatsächlich versehentlich bietet mir die Lösung, die ich will. Ich pvData auf NULL auf _HOOK_FREE und nicht auf Probleme stoßen mit 0xFEEEFEEE für meine Zeigeradresse festlegen

Wenn dies für Sie arbeitet, dann bedeutet es, dass Sie freigegebenen Speicher lesen, wenn Sie für den NULL-Zeiger zu test (dh., Der Zeiger selbst befindet sich im Speicher Sie befreit).

Das ist ein Fehler.

Die ‚Lösung‘ Sie verwenden einfach versteckt, nicht zur Festsetzung der Fehler. Wenn überhaupt, dass freigegebenen Speicher auf etwas anderes zugewiesen wird, plötzlich werden Sie den falschen Wert als Zeiger auf die falsche Sache werden.

Das ist eigentlich ein sehr nettes Feature in VC ++ (und ich glaube, andere Compiler), weil es Dich für einen Zeiger in dem Debugger nicht zugewiesenen Speicher sehen kann. Ich werde zweimal überlegen, bevor diese Funktionalität zu deaktivieren. Wenn Sie ein Objekt in C ++ löschen Sie den Zeiger setzen sollten später, falls etwas zu NULL versucht erneut, das Objekt zu löschen. Diese Funktion ermöglicht es Ihnen, die Orte zu entdecken, wo Sie den Zeiger zu setzen vergessen NULL.

Wenn es im Release-Modus arbeitet, ist es wegen des Scher Glücks.

Mike B richtig ist anzunehmen, dass die Debug-Fix einen Fehler versteckt. In Lösemodus, wird ein Zeiger verwendet, die freigegeben worden sind, aber nicht auf NULL gesetzt, und der Speicher es weist noch „gültig“. An einem gewissen Punkt in der Zukunft, Speicherzuordnungen ändern wird, oder das Speicherbild wird sich ändern, oder etwas bewirkt, dass die „gültige“ Speicherblock „ungültig“ werden. An diesem Punkt wird Ihr Release-Build andernfalls starten. Die Umstellung auf den Debug-Modus zu finden, das Problem wird nutzlos sein, weil der Debug-Modus ist „fixiert“.

Ich denke, wir rufen alle einig, dass der folgende Code nicht funktionieren sollte.

char * p = new char[16];     // 16 bytes of random trash
strcpy(p, "StackOverflow");  // 13 characters, a '\0' terminator, and two bytes of trash
delete [] p;                 // return 16 bytes to the heap, but nothing else changes;

if (p != NULL)               // Why would p be NULL?  It was never set to NULL
    ASSERT(p[0] == 'S');     // In debug, this will crash, because p = 0xfeeefeee and 
                             // dereferencing it will cause an error.
                             // Release mode may or may or may not work, depending on
                             // other memory operations

Wie fast jedes anderes Plakat gesagt hat, sollten Zeiger eingestellt werden nach dem Aufruf von NULL delete. Ob Sie es selbst oder die Verwendung Schub oder eine andere Wrapper oder auch das Makro in diesem Thread tun, ist bis zu Ihnen.

  

Was passiert ist mein Code stürzt ab   unter einer Debug-Kompilation, aber   gelingt es unter einem Release Kompilation.

Releasebuild wird auf Kundenwunsch Maschine zum Absturz bringen. Es ist immer der Fall ist.

  

Ich habe es unter einem Debugger überprüft und   meine Zeiger werden immer auf   0xFEEEFEEE nachdem ich rufe löschen   sie.

Pointers werden nicht geändert, nachdem Sie sie löschen aufrufen. Es ist die Erinnerung sie zu diesem Punkt wird auf 0xfeeefeee, 0xfeeefeee, ..., 0xfeeefeee.

Wenn Sie erkennen, dass Ihr Programm liest Daten aus freigegebenen Speicher (die bequem durch 0xfeeefeee Muster in DEBUG Build angegeben ist), haben Sie einen Fehler.

@ [Jeff Hubbard]:

  

Was passiert ist mein Code stürzt unter einer Debug-Kompilierung, aber erfolgreich unter einem Release Kompilation. Ich habe es unter einem Debugger überprüft und meine Zeiger gesetzt bekommen 0xFEEEFEEE nachdem ich sie anrufen löschen. Auch hier hat derselbe Code auf Release nicht abstürzt und wie erwartet verhält.

Das ist sehr seltsames Verhalten - ich immer noch davon überzeugt bin, dass es wahrscheinlich ein latenter Fehler, der durch die _CrtSetAllocHook() Abhilfe versteckt wird

.

Die 0xFEEEFEEE Signatur wird durch das OS Heap-Manager verwendet freigegebenen Speicher, um anzuzeigen (siehe http : //www.nobugs.org/developer/win32/debug_crt_heap.html ). Durch eine Chance können Sie schreiben einige Repro-Code und zeigen genau, welche Compiler Version Sie verwenden?

Ich bin mir ziemlich sicher, dass Sie nicht den Visual Studio Standard hier deaktivieren können, und selbst wenn Sie der Wert dann nur täten, würde sein, was auch immer in Erinnerung war, bevor der Speicher zugewiesen wurde.

Ihre beste dran, nur die Gewohnheit, bekommen sie auf 0 an erster Stelle der Einstellung, es ist nur 2 zusätzliche charecters.

int *ptr=0;

Sie können auch den NULL-Makro verwenden können, die als 0 (aber nicht standardmäßig definiert ist, so carful sein mit mehreren Definitionen, wenn Sachen wie windows.h includeing und definieren Sie es selbst!

Wenn Sie malloc verwenden, wird es nicht die Erinnerung an etwas intialize. Sie bekommen, was auch immer. wenn Sie möchten, um einen Block reservieren und initialisieren es auf 0, verwenden Sie ‚calloc‘, die wie malloc ist nur mit der Initialisierung (ein ein Element Größenparameter, die Sie auf 1 gesetzt, wenn Sie malloc nacheifern wollen). Sie calloc, bevor Sie es lesen sollte, da es einige geringfügige Unterschiede hat.

http://wiki.answers.com/Q/What_is_the_difference_between_malloc_and_calloc_functions

Warum Ihre eigene #define nicht erstellen und verwenden es in der Gewohnheit?

d.

#define SafeDelete(mem) { delete mem; mem = NULL; }
#define SafeDeleteArray(mem) { delete [] mem; mem = NULL; }

Natürlich können Sie nennen es, was Sie wollen. deleteZ, deletesafe, was auch immer für Sie akzeptabel.

Sie können einen Speichermanager auch erstellen. Dann könnten Sie neue überschreiben und löschen von ziehen / legte ein vorbelegt Futter Speicher zurück.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top