auto_ptr
-
ich verwende folgende Funktion um die Ports der seriellen Schnittstellen auszulesen:
void TfrmMain::LoadPorts(TStrings* portliste) { TStringList* keys(new TStringList()); std::auto_ptr<TRegistry> registry(new TRegistry); registry->Access = KEY_READ; registry->RootKey = HKEY_LOCAL_MACHINE; registry->OpenKey("HARDWARE\\DEVICEMAP\\SERIALCOMM\\", false); registry->GetValueNames(keys); portliste->Clear(); for(int i=0;i<keys->Count;i++) portliste->Add(registry->ReadString(keys->Strings[i])); registry->CloseKey(); delete keys; }
Um Memory Leaks zu vermeiden wurde mir empfohlen Autopointer zu verwenden. Im Forum hier wurde mir aut_ptr empfohlen. Im C++Buch von Kaiser steht, dass der shared_ptr bevorzugt werden soll. Einzubinden ist dieser mit:
#include <boost/shared_ptr.hpp> using boost::shared_ptr;
Dies erzeugt bei mir leider folgende Fehlermeldungen:
[C++ Fehler] unitMain.cpp(18): E2209 include-Datei 'boost/shared_ptr.hpp' kann nicht geöffnet werden. [C++ Fehler] unitMain.cpp(19): E2090 Qualifizierer 'boost' ist kein Name einer Klasse oder einer Struktur [C++ Fehler] unitMain.cpp(19): E2272 Bezeichner erwartet
Kann ich das in der Zeile:
std::auto_ptr<TRegistry> registry(new TRegistry);
mit dem auto_ptr so machen?
Die Stringliste hätt ich auch gern mit einem Autopointer erstellt. Das funktioniert aber nicht, da die Zeile
registry->GetValueNames(keys);
eine Adresse erwartet und dann einen Fehler ausspuckt:
[C++ Fehler] unitMain.cpp(50): E2342 Keine Übereinstimmung des Typs beim Parameter 'Strings' ('TStrings *' erwartet, 'std::auto_ptr<TStringList>' erhalten)
Oder macht es hier vielleicht gar keinen Sinn Autopointer einzusetzen?
-
Hast Du boost denn überhaupt installiert und in den Buildprozess eingebaut? Wenn nicht, kann er den shared_ptr von boost auch nicht finden
Ja, es macht Sinn, Smartpointer zu verwenden, da Du nicht in die Falle tappen kannst, ein delete zu vergessen. Am Beispiel Deiner Stringliste sieht man es, dort hast Du es nämlich vergessen. Ich meine damit nicht das "delete keys" am Ende der Funktion, das ist natürlich ok, aber wenn einer der Aufrufe davor eine Exception wirft, wird dieses delete nie erreicht.
registry->GetValueNames(keys) kann nicht funktionieren, wenn keys ein auto_ptr<TStringList> ist, da ein TStringList* erwartet wird. Aber um aus einem Smartpointer (egal welcher Art) wieder einen rohen Zeiger für die Übergabe an solche APIs zu machen, gibt es ein gängiges Idiom: &*keys (mit *keys machst Du aus dem auto_ptr<TStringList> ein TStringList& und mit dem & machst Du aus dem TStringList& ein TStringList*).
-
Welche BCB Version benutzt du? Die boost Bibliotheken sind erst ab 2009 dabei, wenn du einen älteren Compiler benutzt musst du sie erst selbst übersetzen (v1.34_2 ist da aber Ende der Fahnenstange).
Zum eigentlichen Problem:
Registry->GetValueNames()
erwartet Parameter welchen Typs? Und was übergibst du? Du solltest mal einen Blick in die Hilfe werfen, da steht alles drin, um dein triviales Problem zu lösen.
Edit:
zu langsam
-
Hallo
In deinem Fall ist std::auto_ptr auch ausreichend.
Eine Alternative zu &* ist noch die Methode get :registry->GetValueNames(keys.get());
bis bald
akari
-
Im Forum hier wurde mir auto_ptr empfohlen.
Sicher? Schon lange vor dem neuen Standard wurde davon abgeraten.
-
Hallo
Man muß davon abraten, std::auto_ptr außerhalb der vorgesehenen Möglichkeiten zu benutzen. Gegen eine sachgemäße Benutzung wie in diesem Fall ist nichts einzuwenden. Gerade bei der VCL kann man den auto_ptr gut gebrauchen, weil viele Klassen keine Stackinstanzen zulassen, auch wenn konkret keine größere Gültigkeit gebraucht wird.
bis bald
akari
-
ich verwende den Borland Builder 5. Den boost hab ich nicht installiert. Ist das bei dieser Version überhaupt möglich bzw. erforderlich?
-
rudpower schrieb:
Ist das bei dieser Version überhaupt möglich bzw. erforderlich?
Für so eine Anwendung, wo ein Zeiger auf ein VCL-Objekt innerhalb einer Funktion verwaltet werden soll, reicht auto_ptr völlig aus. Das war zu Zeiten des C++ Builders 5/6 so üblich und es dürfte ziemlich viel Code geben, wo das vorkommt.
Das auto_ptr wegen seiner Designschwächen in modernem C++ nicht mehr verwendet werden sollte, ist mir auch klar. Aber mit dem BCB5 schreibt man kein modernes C++.
Wenn man trotzdem mit Boost arbeiten will, muss man in der Tat sehen mit welcher (alten) Version das geht. Installieren muss man Boost dazu aber nicht, es reicht es irgendwohin zu entpacken. Die Smartpointer sind laut Boost-Webseite header-only und seit Version 1.23 dabei.
-
Der BCB5 arbeitet ganz brauchbar mit boost 1.34 zusammen.
Unter folgendem Link findet man ein Kompatibilitätspaket dafür.
http://sourceforge.net/projects/bcbboost/files/bcbboost-1_34_0-5_9_0/0.1/
Bei Verwendung von boost wäre hier statt shared_ptr eher scoped_ptr geeignet.
-
Kann jemand etwas zu denn Nachteilen des auto_ptr schreiben bzw verlinken?
Mir ist momentan nämlich nicht klar warum dieser nicht mehr verwendet werden soll, bzw. wo die schwächen liegen und was als Ersatz dienen soll.
Sorry für die eventuell dumme Frage?
Danke.
-
Einen Link wird vielleicht noch jemand posten.
Das Problem beim auto_ptr ist der Besitzübergang bei Zuweisung. Dadurch kann sehr schnell Code entstehen, wo man nicht mehr sieht, welchem auto_ptr das Objekt gerade gehört. Insbesondere, wenn jemand auf die dumme Idee kommt einen vector<auto_ptr<irgendwas>> oder ähnliches anzulegen.
boost::scoped_ptr bzw. std::unique_ptr erlauben nur explizites Löschen, Verschieben oder Neuzuweisen über Memberfunktionen bzw. std::move.
-
ich wollte eine ini-Datei mit dem auto_ptr anlegen um mir das delete zu sparen. Das scheint nicht zu funktionieren:
std::auto_ptr<TIniFile> ini(new TIniFile(ChangeFileExt(Application->ExeName, ".INI"));
Ich erhalte flg. Fehler:
[C++ Fehler] unitMain.cpp(155): E2108 Ungültige Verwendung von typedef 'auto_ptr<TIniFile>'
oder mach ich was falsch?
Edit: "vor den Kopf schlag"
Da fehlt eine Klammer.