Frage

Ich habe auf einige legacy C ++ Code arbeitet, die mit variabler Länge Strukturen (TAPI) verwendet, wobei die Strukturgröße auf Zeichenfolgen variabler Länge ab. Die Strukturen zugeordnet sind von Array new Gießen so:

STRUCT* pStruct = (STRUCT*)new BYTE [sizeof(STRUCT) + nPaddingSize];

Später jedoch der Speicher freigegeben wird einen delete Anruf mit:

delete pStruct;

Wird diese Mischung aus Array new [] und Nicht-Array delete einen Speicherverlust verursachen oder würde es auf dem Compiler ab? Würde ich besser dran, diesen Code zu ändern malloc zu verwenden und free statt?

War es hilfreich?

Lösung

Technisch halte ich es für ein Problem mit nicht Übereinstimmen Verteilern führen könnte, obwohl in der Praxis weiß ich nicht von jedem Compiler, der das Richtige mit diesem Beispiel nicht tun würde.

Noch wichtiger ist, wenn STRUCT wo man (oder jemals gegeben werden) ein destructor dann wäre es die destructor aufrufen, ohne den entsprechenden Konstruktor aufgerufen zu haben.

Natürlich, wenn Sie wissen, wo pStruct kam, warum es nicht einfach gießt löscht die Zuordnung entsprechen:

delete [] (BYTE*) pStruct;

Andere Tipps

Ich persönlich denke, würden Sie besser dran std::vector mit Ihrem Speicher zu verwalten, so dass Sie die delete nicht benötigen.

std::vector<BYTE> backing(sizeof(STRUCT) + nPaddingSize);
STRUCT* pStruct = (STRUCT*)(&backing[0]);

Sobald Träger Rahmen verlässt, Ihr pStruct nicht mehr gültig ist.

Alternativ können Sie verwenden:

boost::scoped_array<BYTE> backing(new BYTE[sizeof(STRUCT) + nPaddingSize]);
STRUCT* pStruct = (STRUCT*)backing.get();

oder boost::shared_array wenn Sie brauchen um das Eigentum zu bewegen.

Ja, es wird ein Speicherleck verursachen.

Diese Siehe Ausnahme von C ++ Gotchas: http://www.informit.com/articles/article.aspx?p=30642 warum.

Raymond Chen hat eine Erklärung dafür, wie Vektor new und delete unterscheiden sich von den skalaren Versionen unter den Abdeckungen für die Microsoft-Compiler ... Hier: http://blogs.msdn.com/oldnewthing/archive/2004/02/03/66660.aspx

IMHO sollten Sie reparieren das Löschen zu:

delete [] pStruct;

anstatt Schalt / malloc free, nur wenn weil es ein einfacher Wechsel, ohne Fehler zu machen;)

Und natürlich, um die einfachere Änderung vornehmen, die ich oben zeigen aufgrund des Gießens in der ursprünglichen Zuordnung falsch ist, sollte es sein

delete [] reinterpret_cast<BYTE *>(pStruct);

so, ich denke, es ist wahrscheinlich so einfach zu malloc / free zu wechseln, nachdem alle;)

Das Verhalten des Codes ist nicht definiert. Sie können glücklich sein (oder nicht), und es kann mit dem Compiler arbeiten, aber das ist wirklich nicht korrekter Code. Es gibt zwei Probleme mit sich:

  1. Die delete sollte ein Array delete [] sein.
  2. Die delete sollte auf einen Zeiger auf den gleichen Typ wie der zugewiesenen Typ genannt werden.

So ganz korrekt sein, wollen Sie so etwas zu tun:

delete [] (BYTE*)(pStruct);

Der C ++ Standard eindeutig fest:

delete-expression:
             ::opt delete cast-expression
             ::opt delete [ ] cast-expression
  

Die erste Alternative ist für Nicht-Array-Objekte, und das zweite ist für Arrays. Der Operand wird einen Zeigertyp hat, oder einen Klassentyp eine einzelne Umsetzungsfunktion (12.3.2) auf einen Zeigertyp aufweist. Das Ergebnis hat Typ void.

     

Bei der ersten Alternative (Objekt löscht) wird der Wert des Operanden der Lösch- wird ein Zeiger auf ein Nicht-Array-Objekt sein [...] Wenn nicht, ist das Verhalten nicht definiert.

Der Wert des Operanden in delete pStruct ist ein Zeiger auf ein Feld von char, unabhängig von seinem statischen Typ (STRUCT*). Daher wird jede Diskussion von Speicherlecks ist ziemlich sinnlos, da der Code ist schlecht ausgebildet, und ein C ++ Compiler ist nicht eine vernünftige ausführbare Datei in diesem Fall zu erzeugen, erforderlich.

Es könnte ein Speicherleck auf, es kann nicht, oder es könnte alles tun, bis Ihr System abstürzt. Tatsächlich ist eine C ++ Implementierung, mit dem ich den Code getestet bricht die Programmausführung an der Stelle des Lösch Ausdrucks.

Wie in anderen Beiträgen hervorgehoben:

1) fordert neue / löschen Speicher zuweisen und Konstrukteuren nennen / Destruktoren (C ++ '03 5.3.4 / 5.3.5)

2) Misch Array / Nicht-Array-Versionen von new und delete ist nicht definiertes Verhalten. (C ++ '03 5.3.5 / 4)

Mit Blick auf die Quelle scheint es, dass jemand eine Suche gemacht und für malloc und free ersetzen und das oben ist das Ergebnis. C ++ hat für diese Funktionen einen direkten Ersatz hat, und das ist die Zuordnungsfunktionen für new und delete direkt anzurufen:

STRUCT* pStruct = (STRUCT*)::operator new (sizeof(STRUCT) + nPaddingSize);
// ...
pStruct->~STRUCT ();  // Call STRUCT destructor
::operator delete (pStruct);

Wenn der Konstruktor für STRUCT aufgerufen werden soll, dann betrachten Sie könnte die Zuweisung von Speicher und dann Platzierung new verwenden:

BYTE * pByteData = new BYTE[sizeof(STRUCT) + nPaddingSize];
STRUCT * pStruct = new (pByteData) STRUCT ();
// ...
pStruct->~STRUCT ();
delete[] pByteData;

@eric - Danke für die Kommentare. Sie sagen immer, wenn etwas, das mich verrückt fährt:

  

Diese Laufzeitbibliotheken behandeln die   Speicherverwaltung ruft das Betriebssystem in einem   OS unabhängig konsistente Syntax und   diese Laufzeitbibliotheken sind   verantwortlich für die Herstellung von malloc und neuen   konsequent zwischen OSes arbeiten wie   Linux, Windows, Solaris, AIX, etc ....

Das ist nicht wahr. Der Compiler Schriftsteller stellt die Implementierung der Standardbibliotheken, zum Beispiel, und sie sind absolut kostenlos die in einem O abhängige Art und Weise umzusetzen. Sie sind frei, zum Beispiel, aber einen großen Aufruf von malloc zu machen, und dann Speicher verwalten innerhalb des Blockes aber sie wollen.

Kompatibilität zur Verfügung gestellt wird, weil die API von std usw. die gleiche ist - nicht, weil die Laufzeitbibliotheken rundum drehen und exakt die gleichen OS Anrufe rufen

.

Die verschiedenen Einsatzmöglichkeiten der Schlüsselwörter neu und löschen Sie scheinen ziemlich viel Verwirrung zu stiften. Es gibt immer zwei Stufen auf die Konstruktion von dynamischen Objekten in C ++: die Zuordnung des Ausgangsspeichers und der Bau des neuen Objekts in dem Speicherbereich zugeordnet. Auf der anderen Seite des Objektlebensdauer gibt es die Zerstörung des Objekts und die Aufhebung der Zuordnung des Speicherplatzes, wo das Objekt residiert.

Häufig diese beiden Schritte durch eine einzige C ++ Anweisung ausgeführt werden.

MyObject* ObjPtr = new MyObject;

//...

delete MyObject;

Statt der oben Sie die C ++ rohen Speicherzuordnungsfunktionen operator new und operator delete und explizite Konstruktion (über die Platzierung new) verwenden können und Zerstörung die entsprechenden Schritte auszuführen.

void* MemoryPtr = ::operator new( sizeof(MyObject) );
MyObject* ObjPtr = new (MemoryPtr) MyObject;

// ...

ObjPtr->~MyObject();
::operator delete( MemoryPtr );

Beachten Sie, wie es kein Casting beteiligt ist, und nur eine Art von Objekt wird in dem zugewiesenen Speicherbereich aufgebaut. Mit so etwas wie new char[N] als Weg, um rohe Speicher zuzuordnen ist technisch falsch, da logischerweise sind char Objekte in der neu zugewiesenen Speicher erstellt. Ich weiß nicht, von jeder Situation, wo es nicht ‚einfach funktionieren‘, sondern es verwischt den Unterschied zwischen Roh Speicherzuordnung und Objekterstellung so dass ich davon abraten.

In diesem speziellen Fall gibt es keine Verstärkung durch Trennen Sie die beiden Schritte delete werden musste, aber Sie müssen manuell die Erstzuteilung steuern. Der obige Code funktioniert in dem ‚alles funktioniert‘ Szenario, aber es wird den rohen Speicher im Fall auslaufen, wo der Konstruktor von MyObject eine Ausnahme auslöst. Während diese gefangen und mit einem Exception-Handler an der Stelle der Zuteilung gelöst werden könnte es ist wahrscheinlich ordentlicheres neue einen benutzerdefinierten Operator bereitzustellen, so dass die gesamte Konstruktion durch eine Platzierung neuen Ausdruck gehandhabt werden kann.

class MyObject
{
    void* operator new( std::size_t rqsize, std::size_t padding )
    {
        return ::operator new( rqsize + padding );
    }

    // Usual (non-placement) delete
    // We need to define this as our placement operator delete
    // function happens to have one of the allowed signatures for
    // a non-placement operator delete
    void operator delete( void* p )
    {
        ::operator delete( p );
    }

    // Placement operator delete
    void operator delete( void* p, std::size_t )
    {
        ::operator delete( p );
    }
};

Es gibt ein paar subtile Punkte hier. Wir definieren eine Klasse Platzierung neu, so dass wir genug Speicher für die Klasseninstanz sowie einige Benutzer vorgebbare padding zuordnen kann. Weil wir dies tun, müssen wir eine passende Platzierung schaffen, zu löschen, so dass, wenn die Speicherzuordnung gelingt aber der Bau fehlschlägt, wird der reservierte Speicher automatisch freigegeben. Leider löschen die Signatur für unsere Platzierungsspiele einer der beiden erlaubt Signaturen für nicht-Platzierung löschen, so müssen wir die andere Form von nicht-Platzierung schaffen, löschen, so dass unsere reale Platzierung löschen behandelt wird, als eine Platzierung löschen. (Wir um diese bekommen haben könnte durch Hinzufügen eines zusätzlichen Dummy-Parameter sowohl für unsere Platzierung neue und Platzierung löschen, aber diese zusätzliche Arbeit an allen Standorten Aufruf bedurft hätte.)

// Called in one step like so:
MyObject* ObjectPtr = new (padding) MyObject;

einen einzigen neuen Ausdruck verwenden wir garantieren jetzt, dass der Speicher nicht auslaufen, wenn ein Teil des neuen Ausdrucks führt.

Am anderen Ende des Objektlebensdauer, weil wir Operator löscht definiert (auch wenn wir nicht, die Speicher für das Objekt hatten ursprünglich kamen von den globalen Operator neu in jedem Fall), ist die folgend der richtige Weg, das zu zerstören, dynamisch Objekt erstellt hat.

delete ObjectPtr;

Zusammenfassung!

  1. keine Abgüsse Schau! operator new und operator delete Deal mit rohen Speicher, Platzierung neue Objekte können im Raw-Speicher konstruieren. Eine explizite Umwandlung von einem void* auf einen Objektzeiger ist in der Regel ein Zeichen für etwas logisch falsch, auch wenn es nicht ‚einfach funktionieren‘.

  2. Wir haben völlig neue ignoriert [] und delete []. Diese variablen Größe Objekte werden nicht in Arrays in jedem Fall arbeiten.

  3. Placement neue ermöglicht ein neuer Ausdruck zu lecken nicht, wertet der neue Ausdruck immer noch auf einen Zeiger auf ein Objekt, das Speicher vernichtet werden muss und das Aufheben der Zuordnung muss. Verwendung von irgendeiner Art von Smart-Pointer helfen andere Arten von Lecks zu verhindern. Auf der positiven Seite haben wir eine einfache delete sein die richtige Art und Weise arbeiten lassen diese so die meisten Standard-Smart-Pointer werden zu tun.

Wenn Sie wirklich muss diese Art der Sache tun, sollten Sie wahrscheinlich Operator new direkt anrufen:

STRUCT* pStruct = operator new(sizeof(STRUCT) + nPaddingSize);

Ich glaube, ruft es auf diese Weise vermeidet Konstrukteuren / Destruktoren aufrufen.

Ich bin derzeit nicht in der Lage zu wählen, aber slicedlime Antwort vorzuziehen Rob Walker Antwort , da das Problem hat nichts mit Verteilern zu tun oder ob die STRUCT eine destructor hat.

Beachten Sie auch, dass der Beispielcode notwendigerweise in einem Speicherleck nicht zur Folge hat - es nicht definiertes Verhalten ist. So ziemlich alles (von nichts Schlechtes zu einem Absturz weit, weit weg) passieren könnte.

Der Beispielcode führt zu undefiniertem Verhalten, schlicht und einfach. slicedlime Antwort ist direkt und auf den Punkt (mit dem Vorbehalt, dass das Wort ‚Vektor‘ sollte auf ‚Array‘ geändert werden, da Vektoren eine STL Sache ist).

Diese Art von Zeug ist ziemlich gut in der C ++ FAQ abgedeckt (Abschnitte 16.12, 16.13 und 16.14):

http://www.parashift.com /c++-faq-lite/freestore-mgmt.html#faq-16.12

Es ist ein Array löschen ([]) Sie sich beziehen, kein Vektor löschen. Ein Vektor ist std :: vector, und es kümmert sich um Löschung seiner Elemente.

Sie würden könnte zu einem BYTE * zurückgeworfen und löschen:

delete[] (BYTE*)pStruct;

Ja, das Mai, da Ihre mit neuer Zuteilung [], aber das Aufheben von Zuweisungen mit delelte, ja malloc / free ist hier sicherer, aber in C ++ Sie sollten sie nicht verwendet werden, da sie nicht (de) Bauer behandeln.

Auch Ihr Code wird das Deconstructor nennen, aber nicht der Konstruktor. Für einige structs kann dies ein Speicherleck verursachen (wenn der Konstruktor weitere Speicher zugewiesen, für einen String zB)

Besser wäre es richtig zu tun, da dies auch richtig alle Konstrukteure anrufen und deconstructors

STRUCT* pStruct = new STRUCT;
...
delete pStruct;

Es ist immer am besten Erwerb / Freigabe aller Ressourcen so ausgeglichen wie möglich zu halten. Obwohl undicht oder nicht schwer ist, in diesem Fall zu sagen. Es hängt von der Implementierung des Compilers des Vektors (de) Zuordnung.

BYTE * pBytes = new BYTE [sizeof(STRUCT) + nPaddingSize];

STRUCT* pStruct = reinterpret_cast< STRUCT* > ( pBytes ) ;

 // do stuff with pStruct

delete [] pBytes ;

Len: das Problem mit diesem ist, dass pStruct ein STRUCT *, aber der Speicher zugewiesen ist eigentlich ein byte [] einer unbekannten Größe. So löschen [] pStruct werden alle der zugewiesenen Speicher nicht de-zuweisen.

Sie sind Misch Art von C und C ++ Möglichkeiten, Dinge zu tun. Warum mehr als die Größe eines STRUCT zuteilen? Warum nicht nur „neuer STRUCT“? Wenn Sie dies tun müssen, dann könnte es klarer sein malloc und frei in diesem Fall zu verwenden, da dann könnten Sie oder andere Programmierer ein wenig weniger wahrscheinlich auf Annahmen über die Art und Größe der zugeordneten Objekte.

@ Matt Cruikshank Sie sollten darauf achten und lesen, was ich wieder geschrieben, weil ich vorschlug nie nicht [] Aufruf löschen und lassen nur das Betriebssystem aufzuräumen. Und du bist falsch über die C ++ Laufzeitbibliotheken die Heap-Verwaltung. Wenn das der Fall wäre, dann würde C ++ nicht tragbar sein wie heute und eine abstürzende Anwendung würde nie von den OS gereinigt bekommen. (Anerkennung gibt es OS-spezifische Laufzeiten, die C / C ++ machen erscheinen nicht tragbar). Ich fordere Sie stdlib.h in den Linux-Quellen von kernel.org zu finden. Das neue Schlüsselwort in C ++ ist tatsächlich im Gespräch mit den gleichen Speicherverwaltungsroutinen wie malloc.

Die C ++ Laufzeitbibliotheken machen OS-Systemaufrufe und es ist das Betriebssystem, das den Haufen verwaltet. Sie sind richtig in zum Teil, dass die Laufzeitbibliotheken anzuzeigen, wenn jedoch den Speicher freizugeben, sie gehen nicht wirklich keine Heap-Tabellen direkt. Mit anderen Worten, die Laufzeit Sie gegen Link nicht-Code in Ihrer Anwendung hinzufügen Haufen zu gehen oder ausplanen zuzuordnen. Dies ist der Fall in Windows, Linux, Solaris, AIX, etc ... Es ist auch der Grund, Sie werden nicht in Ordnung malloc in Kernel-Source-Linux noch werden Sie stdlib.h in Linux Quelle finden. Verstehen Sie dieses moderne Betriebssystem hat die virtuellen Speicher-Manager, dass die Dinge ein bisschen weiter erschwert.

Überhaupt sich wundern, warum Sie einen Aufruf von malloc für 2G RAM auf einem 1G Box machen und noch einen gültigen Speicherzeiger zurück?

Speicherverwaltung auf x86-Prozessoren innerhalb Kernel Raum verwaltet mit drei Tabellen. PAM (Seite Allocation Table), PD (Seite Verzeichnisse) und PT (Page Tables). Dies ist auf der Hardwareebene ich spreche. Eines der Dinge, die OS-Speicher-Manager tut, nicht Ihre C ++ Anwendung ist, um herauszufinden, wie viel physischer Speicher auf dem Feld während des Bootvorgangs mit Hilfe von BIOS-Aufrufe installiert ist. Das Betriebssystem übernimmt auch Ausnahmen wie wenn Sie versuchen, auf Speicher zuzugreifen Ihre Anwendung Rechte nicht haben. (GPF allgemeine Schutzverletzung).

Es kann sein, dass wir die gleiche Sache Matt sagen, aber ich denke, man kann die unter der Motorhaube Funktionalität ein wenig verwirrend sein. Ich benutze einen C / C ++ Compiler für ein Leben zu halten ...

@ericmayo - cripes. Nun, das Experimentieren mit VS2005, ich kann nicht eine ehrliche Leck aus skalaren lösche auf Speicher erhalten, die durch den Vektor neu gemacht wurde. Ich denke, das Compiler Verhalten hier „undefiniert“ ist, geht es um die beste Verteidigung ich aufbringen kann.

Sie haben allerdings zugeben, es ist ein wirklich mieses Praxis zu tun, was das ursprüngliche Plakat sagte.

  

Wenn das der Fall wäre, dann würde C ++   nicht tragbar sein wie heute und a   würde Anwendung abstürzt nie bekommen   durch das Betriebssystem gereinigt.

Diese Logik gilt nicht wirklich, though. Meine Behauptung ist, dass ein Compiler-Laufzeit den Speicher innerhalb der Speicherblöcke verwalten kann, dass das Betriebssystem, um es zurückgibt. Dies ist, wie die meisten virtuellen Maschinen arbeiten, so dass Ihr Argument gegen Portabilität in diesem Fall nicht viel Sinn machen.

@ Matt Cruikshank

"Nun, mit VS2005 zu experimentieren, kann ich nicht eine ehrliche Leck aus skalaren lösche auf Speicher erhalten, die durch den Vektor gemacht wurde neu. Ich denke, das Compiler Verhalten ist‚undefined‘hier geht es um die beste Verteidigung ich aufbringen kann ".

Ich bin nicht einverstanden, dass es ein Compiler Verhalten oder sogar ein Compiler Problem. Die ‚neuen‘ Schlüsselwort wird kompiliert und verknüpft, wie Sie wies darauf hin, Bibliotheken zu Zeit laufen. Diese Laufzeitbibliotheken behandeln die Speicherverwaltung in einer betriebssystemunabhängige konsistenten Syntax zum O ruft und diese Laufzeitbibliotheken sind verantwortlich für die Herstellung von malloc und neue Arbeit konsequent zwischen OSes wie Linux, Windows, Solaris, AIX, etc ... . Dies ist der Grund, warum ich das Portabilität Argument erwähnt; ein Versuch, Ihnen zu beweisen, dass die Laufzeit nicht tatsächlich Speicher entweder verwalten.

Das Betriebssystem verwaltet den Speicher.

Die Laufzeit Libs Schnittstelle zum O .. Unter Windows ist dies die virtuelle Speicher-Manager DLLs. Aus diesem Grunde stdlib.h innerhalb der GLIB-C-Bibliotheken implementiert ist und nicht die Linux-Kernel-Quelle; wenn GLIB-C auf anderen Betriebssystemen verwendet wird, ist es Implementierung von malloc Veränderungen die richtigen OS Anrufe zu tätigen. In VS, Borland, etc .. Sie werden nie alle Bibliotheken finden, die mit ihren Compiler liefern, die tatsächlich Speicher entweder verwalten. Sie werden jedoch betriebssystemspezifische Definitionen für malloc finden.

Da wir die Quelle zu Linux haben, können Sie gehen sehen, wie malloc es umgesetzt wird. Sie werden sehen, dass malloc tatsächlich in den GCC-Compiler, der wiederum implementiert ist, macht im Grunde zwei Linux-System in den Kernel ruft Speicher zuzuweisen. Nie, malloc selbst, eigentlich Speicher verwalten!

Und nehmen Sie sich nicht von mir. Lesen Sie den Quellcode auf Linux OS oder Sie können sehen, was K & R darüber sagen ... Hier ist ein PDF-Link auf die K & R auf C.

http://www.oberon2005.ru/paper/kr_c.pdf

Sehen Sie in der Nähe von Ende Seite 149: „Anrufe auf malloc und frei in beliebiger Reihenfolge auftreten können; malloc Anrufe von dem Betriebssystem, um mehr Speicher als notwendig zu erhalten. Diese Routinen zeigen einige der beteiligten Überlegungen in schriftlicher Form maschinenabhängigen Code in eine relativ machineindependent Weise und zeigen auch eine reale Anwendung von Strukturen, Gewerkschaften und typedef. "

„Du musst allerdings zugeben, es ist ein wirklich mieses Praxis zu tun, was das ursprüngliche Plakat, sagte.“

Oh, ich nicht da anderer Meinung. Mein Punkt war, dass der Code des Original-Poster nicht förderlich für einen Speicherverlust war. Das ist alles, was ich sagte. Ich habe läuten nicht auf dem Best-Practice-Seite der Dinge in. Da der Code löschen anruft, wird der Speicher frei bis zu bekommen.

Ich bin damit einverstanden, in der Verteidigung, wenn das Code der Original-Poster nie verlassen oder es nie zu dem Lösch Anruf, dass der Code ein Speicherleck haben könnte, aber da er, dass später heißt es auf ihn die delete immer genannt sieht. „Später jedoch der Speicher freigegeben wird, einen Lösch-Aufruf:“

Darüber hinaus mein Grund für die Reaktion, wie ich war auf die Bemerkung des OP „mit variabler Länge Strukturen (TAPI), wo die Strukturgröße auf Zeichenfolge variabler Länge abhängen“ due tat

Dieser Kommentar klang wie er die Dynamik der Zuweisungen gegen die Besetzung in Frage gestellt werden, und folglich habe mich gefragt, ob das einen Speicherverlust verursachen würde. Ich war zwischen den Zeilen zu lesen, wenn man so will.;)

Zusätzlich zu den ausgezeichneten Antworten oben, würde ich auch hinzufügen:

Wenn Ihr Code läuft auf Linux oder, wenn Sie es auf Linux kompilieren kann dann würde ich vorschlagen, es durch Laufen Valgrind . Es ist ein ausgezeichnetes Werkzeug, unter der Vielzahl von nützlichen Warnungen es wird auch sagen, Ihr erzeugt, wenn Sie Speicher als ein Array zuweisen und sie dann frei als Nicht-Array (und umgekehrt).

Verwenden Operator neu und löschen:

struct STRUCT
{
  void *operator new (size_t)
  {
    return new char [sizeof(STRUCT) + nPaddingSize];
  }

  void operator delete (void *memory)
  {
    delete [] reinterpret_cast <char *> (memory);
  }
};

void main()
{
  STRUCT *s = new STRUCT;
  delete s;
}

Ich denke, das ist kein Speicherverlust.

STRUCT* pStruct = (STRUCT*)new BYTE [sizeof(STRUCT) + nPaddingSize];

Dies wird in eine Speicherzuweisung Anruf innerhalb des Betriebssystems übersetzt, auf dem ein Zeiger auf diesen Speicher zurückgeführt wird. Zu der Zeit, Speicher zugewiesen wird, würden die Größe von sizeof(STRUCT) und die Größe der nPaddingSize, um alle Speicherzuordnungsanforderungen gegenüber dem zugrunde liegenden Betriebssystem zu erfüllen bekannt sein.

So ist der Speicher, der zugeordnet wird „aufgezeichnet“ in der globalen Speicherzuordnungstabellen des Betriebssystems. Speichertabellen werden durch ihre Zeiger indiziert. So in der entsprechenden Aufruf zu löschen, werden alle Speicher, der ursprünglich zugewiesen wurde, ist frei. (Speicherfragmentierung ein beliebtes Thema in diesem Bereich als auch).

Sie sehen, der C / C ++ Compiler Speicher nicht die Verwaltung, das zugrunde liegende Betriebssystem ist.

Ich bin damit einverstanden gibt es saubere Methoden, aber die OP sagte dieser Legacy-Code ist.

Kurz gesagt, ich habe nicht ein Speicherleck sehen, wie die akzeptierte Antwort dort glaubt man sein.

Rob Walker antworten ist gut.

Nur kleine Ergänzung, wenn Sie haben keinen Konstruktor oder / und distructors, so müssen Sie im Grunde zuweisen und frei ein Stück roher Speicher, sollten frei / malloc Paar verwendet wird.

ericmayo.myopenid.com ist so falsch, dass jemand mit genug Ruf sollte ihn downvote.

Die C oder C ++ Laufzeitbibliotheken verwalten die Haufen, die es in den Blöcken vom Betriebssystem gegeben ist, ein wenig wie Sie angeben, Eric. Aber es ist in der Verantwortung des Entwicklers an den Compiler, um anzuzeigen, die Laufzeit Anrufe sollten, um Speicher frei gemacht werden, und möglicherweise die Objekte zerstören, die es gibt. Vector löschen (aka löschen []) ist in diesem Fall notwendig, um für die C ++ Runtime den Heap in einem gültigen Zustand zu verlassen. Die Tatsache, dass, wenn der Prozess beendet wird, das Betriebssystem ist intelligent genug, um die zugrunde liegenden Speicherblöcke freizugeben ist nicht etwas, das Entwickler verlassen sollte. Dies wäre wie nie überhaupt Aufruf löschen.

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