2011-01-01 12 views
5

Ich habe überall nach einer Antwort gesucht, kann aber keine finden. (Ich habe ziemlich begrenzte Erfahrung mit C++)Überprüfung, ob ein Zeiger freigegeben werden kann

In meiner Bibliothek gebe ich eine Zeichenfolge frei. (Erstaunlich, nicht wahr?)

Dies ist, wo das Problem auftritt. Ich habe eine Struktur, die ein Zeichen * enthält, das auf dem Heap zugeordnet werden kann oder nicht sein kann. Während es ein gültiger Zeiger ist, kann es nicht freigegeben werden.

IE

char* s1 = "A String"; 
char* s2 = (char*)memcpy(malloc(9), s1, 9); 

free(s2); 
free(s1); 

Wird ein Fehler verursacht auf "frei (s1);" (Wie es sollte) Weil s1 nicht wirklich braucht, um befreit zu werden, (es ist nicht auf dem Haufen) wie kann ich das auf eine "akzeptable" Art und Weise behandeln? (Bei ähnlichen Themen schien die Antwort "lass es abstürzen" nicht angemessen IMO)

Da die Struktur nicht nur von der Bibliothek erstellt wird, ist es nicht möglich zu garantieren, dass eine Zeichenfolge ordnungsgemäß mit etwas überkopiert wird wie memcpy.

Da dies eine Windows-Bibliothek ist, muss ich mich nicht um die Verwendung von ISO C-Stuff oder C-Standardfunktionen kümmern.

+0

Beste Antwort (IMHO): ein undurchsichtigen Zeiger verwenden zu gewährleisten, dass die 'struct' _is_ in der Bibliothek allein erstellt. (Ich würde mehr Hilfe anbieten, wenn ich Windows benutze. Entschuldigung. +1.) –

+0

Danke, wenn es am schlimmsten wird, kann ich das entweder tun oder SEH benutzen (obwohl letzteres mir das Gefühl geben würde, etwas falsch zu machen) – James

+0

Da dies eine Windows-Bibliothek ist, machen Sie das Argument zu einem BSTR. Dann müssen Sie den Benutzer richtig zuordnen (mit 'SysAllocString') und Sie werden garantiert einen passenden Deallocator verwenden. Andere Methoden sind nur ... schlecht. Wenn Ihr Benutzer einen anderen Compiler hat, können Sie den String nicht "frei()", auch wenn er 'malloc' verwendet –

Antwort

2

Da dies eine Windows-Bibliothek ist, geben Sie als Argument BSTR ein. Dann müssen Sie den Benutzer ordnungsgemäß zuordnen (mit SysAllocString) und Sie werden garantiert a matching deallocator verwenden.

Andere Methoden sind nur ... schlecht. Wenn Ihr Benutzer einen anderen Compiler hat, können Sie die Zeichenfolge free() nicht verwenden, selbst wenn sie malloc verwendet haben.

[Hinweis: Umgerechnet aus einem Kommentar zu James Wunsch, das ist wirklich nur ein Windows-spezifischer Fall der letzten von his suggestions]

Weiterer Anmerkung: BSTR Unicode ist. Ich erinnere mich irgendwie daran, einen Weg gesehen zu haben, den BSTR-Allokator zu benutzen, um ANSI-Zeichenketten zu speichern, scheint aber das SysAllocStringByteLen zu tun, aber sei gewarnt, dass ANSI-Daten in einen BSTR zu stellen, sehr intuitiv zu jedem sein wird, der mit BSTR vertraut ist.

+0

In Ordnung, aber ich erinnere mich, dass ich einige schlechte Erfahrungen mit bstr gemacht habe, als ich es (und SAFEARRAY) beim Umgang mit .NET-Code aus nativem C++ verwenden musste. Das ist Off-Thema, aber ich werde es versuchen. – James

+0

@James: Ich vermute, dass es der COM-Code war, der Schwierigkeiten verursachte und nicht BSTR. Die BSTR-Funktionen sind eigentlich sehr einfach und einfach aus C oder C++ zu verwenden. Ich denke, dass VC++ sogar eine Wrapper-Klasse zur Verfügung stellt, um den BSTR automatisch zu befreien, da es den Rahmen sprengt, aber es bringt nicht viel Funktionalität und nicht genau zu wissen, wie es funktioniert, hat mich immer 'SysAllocString' und' SysFreeString genannt 'direkt. –

6

In C++ sollten Sie sich darüber keine Gedanken machen. Verwenden Sie std::string und verwalten Sie den Speicher automatisch für Sie. Don't manage memory manually.

Wenn Sie dies manuell tun wären, müssen Sie die Ressource selbst zu verwalten, von

  • machen den Benutzer der Bibliothek verwaltet den Speicher selbst oder
  • die Benutzer Ihnen sagen, wie man den Speicher verwaltet, oder
  • sagen dem Benutzer, wie Sie den Speicher verwalten und dann erwarten, dass der Benutzer zu erfüllen.
+1

Das ist ein toller Ratschlag, außer dass es (1) eine Bibliothek (2) unter Windows und (3) offenbar vorkompiliert ist, so die Kommentare. Und 'std :: string' wird als unsicher eingestuft, um Modulgrenzen unter Windows zu überschreiten. Nach dem Muster der Win32-API ist das erste von Ihnen angegebene Aufzählungszeichen bei weitem die bevorzugte Methode für die Verarbeitung von Speicher durch Windows-Bibliotheken. –

+0

@Ben: Windows-Programmierung: nicht meine Stärke (lustig, nehme ich an). Sie haben natürlich Recht: Wenn Sie den Build-Prozess für die Bibliothek und die damit verbundenen Links nicht kontrollieren können, wäre das ziemlich problematisch. Ich habe Ihre BSTR-Lösung aktualisiert, wenn Sie sie als Antwort gepostet haben. Das ist die vernünftigste Lösung, IMO. –

0

Sie können malloc char *s1 und "A String" als Wert platzieren. Danach können Sie s1 freigeben.

+0

Ich weiß, aber wenn jemand geht struct-> val = "zufällig"; dann bekomme ich wieder Probleme – James

0

Dies ist die Art der Sache, die zum Zeitpunkt der Kompilierung bekannt ist. Du schaust dir den Code an und weißt, was zu befreien ist und was nicht. Denken Sie also nicht darüber nach, wie Sie es auf die Laufzeit verschieben können, denn abgesehen davon, dass Sie in diesem Fall keinen Weg finden, ist es die falsche Art, Dinge in C++ zu tun. Wenn du es statisch machen kannst, mache es statisch.

Verwenden Sie das Typsystem. Verwende RAII.

+0

Das Problem ist, dass es nicht zur __my__ Kompilierzeit bekannt ist, nur für die Leute, die tatsächlich meine Bibliothek aufrufen. Ein Zeiger ist nur eine Zahl. – James

+1

@James Dies ist über ** Besitz **. Die Frage ist, wem der Zeiger gehört. Das sagen Sie in der Dokumentation der Funktion. In jedem Fall sollte der Anrufer nicht prüfen, ob er den Zeiger freigeben soll oder nicht. Auch dies sind statische Informationen, über die Sie sich im Klaren sein müssen. – wilhelmtell

0

Speichern Sie alle Zeichenfolgen im Heap, dann wissen Sie, dass sie alle freigegeben werden müssen. Wenn die Zeichenfolge wie im globalen Speicher vorhanden ist, kopieren Sie sie in einen Heap-Puffer.

+0

Wessen Haufen? Unter Windows neigt jede Bibliothek dazu, einen eigenen inkompatiblen malloc/free-Heap zu erhalten. Die Win32-API-Funktionen 'HeapAlloc' und' HeapFree' funktionieren über Modulgrenzen hinweg, aber sie sind nicht kompatibel mit CRT-bereitgestellten malloc und frei in jedem der Module. –

+0

Der von malloc() verwendete Heap, wie das OP den String zugewiesen hat, der auf dem Heap gespeichert wurde. –

0

Ich habe in der Vergangenheit etwas Ähnliches gemacht, wo ich in einigen Fällen eine Stack-allokierte Zeichenfolge und in anderen eine Heap-allokierte Zeichenfolge verwenden würde, die aber letztlich an einen anderen gemeinsamen Code übergeben wird.

Was ich in diesem Fall getan habe, ist, zwei Zeiger zu haben. Eins ist entweder NULL oder eine Heap-allokierte Zeichenfolge. Der andere Zeiger zeigt entweder auf den Stapel zugewiesenen oder den gleichen Heapspeicher wie der erstere. Wenn du loslegst, um dein freies() zu tun, prüfst du nur den ehemaligen Zeiger.

Natürlich wird das in einer exponierten API unangenehm aussehen. In meinem Fall war es nur interner Code.

Verwandte Themen