Richtigen Weg zuweisen Zeiger in c++
EDIT: ich weiß, in diesem Fall, wenn es eine tatsächliche Klasse wäre ich besser dran, nicht, den string auf dem heap. Jedoch, dies ist nur ein Beispiel-code, um sicherzustellen, dass ich die Theorie verstehen. Der eigentliche code wird ein rot-schwarz-Baum mit allen Knoten gespeichert, auf dem heap.
Möchte ich sicherstellen, dass ich über diese grundlegenden Vorstellungen zu korrigieren, bevor (ich komme aus einer Java - /Python-hintergrund). Ich habe die Suche im Netz, aber habe nicht gefunden eine konkrete Antwort auf diese Frage noch.
Wenn Sie neu zuordnen, die einen Zeiger auf ein neues Objekt werden müssen, rufen Sie löschen auf das alte Objekt zunächst um Speicherlecks zu vermeiden? Meine intuition sagt mir ja, aber ich will eine konkrete Antwort, bevor Sie fortfahren.
Zum Beispiel lassen Sie sagen, Sie hatte eine Klasse, die gespeichert, ein Zeiger auf einen string
class MyClass
{
private:
std::string *str;
public:
MyClass (const std::string &_str)
{
str=new std::string(_str);
}
void ChangeString(const std::string &_str)
{
//I am wondering if this is correct?
delete str;
str = new std::string(_str)
/*
* or could you simply do it like:
* str = _str;
*/
}
....
In der ChangeString Methode, welche wäre die richtige?
Ich glaube, ich bin immer hängen geblieben, wenn Sie nicht verwenden Sie das neue Schlüsselwort für die zweite Möglichkeit, es wird noch kompilieren und ausführen, wie Sie es erwartet haben. Tut dies einfach überschreiben die Daten, die dieser pointer zeigt? Oder ist es etwas anderes tun?
Jede Beratung wäre sehr appricated 😀
- Es ist wahrscheinlich, dass Sie sollten nicht die Zuweisung einer Zeichenfolge, die mit
new
in den ersten Platz. Hast du irgendeinen besonderen Grund? - Lesen Sie die Bearbeiten oben auf der Seite
- Eine Natürliche Sache zu tun hier, wäre noch:
*str = _str;
(keine Notwendigkeit, wegwerfen, eine string-und die andere erstellen, wenn Sie wollen einfach nur zuordnen, um den Inhalt) - Das ist ziemlich viel, was meine Frage-Zentren über. Wenn ich es auch so gemacht hat, würde ich haben, bekomme ich ein memory-leak? Ab in die Kommentare unten, es klingt wie ich möchte.
- Wenn Sie möchten, ared-schwarz-Baum, was ist Los mit std::map?
- der ganze Zweck des rot-schwarz-Baum ist, nur um mich intruduced, um die Sprache/syntax/etc. Jedes mal, wenn ich abholen eine neue Sprache beginne ich mit dem Bau eines rot-schwarz-Baum, um sicherzustellen, dass ich die Grundlagen zu verstehen (es ist so ziemlich mein "Hallo Welt")
- Natürlich werden Sie nicht bekommen einen memory-leak mit
*str = _str;
(weilstd::string
sich nicht Auslaufen). Beachten Sie, dass dies mit den bestehenden Objekte, nicht Adressen. - @Neil: Alle C++ - Programmierer sollte in der Lage sein, Speicherverwaltung manuell und Umsetzung einer RAII-Klasse mit eingebauten Konstrukte, so gibt es nichts falsch diese Dinge zu tun, als übung. - Danke, das ist genau das, was ich gesucht hatte (war nicht sicher, ob es überschreiben, das Objekt der Zeiger zeigte auf, oder erstellen Sie eine neue irgendwo was in einem memory-leak). Es ist jetzt mein Verständnis, dass '*pObject = DifferentObject' überschrieben werden alte Objekt pObject Punkte zu, und wird nicht in ein memory-leak. Dank
- Es ist nicht akkurat zu sagen, dass
*pObject = DifferentObject
überschreibt das alte Objekt. Er ruft den Zuweisungsoperator der pObject, die wahrscheinlich wird, kopieren Sie die relavent information aus DifferentObject. (Im Fall von std::string, ja, pObject wird am Ende mit dem gleichen Zeichen wie DifferentObject hat.) - Einfach in der Lage zu hacken zusammen ein rot-schwarz-Baum, der kompiliert und scheint zu funktionieren, nicht wirklich lehrt Sie alles nützliche über C++. In C++, die Befriedigung der compiler ist die am wenigsten Ihrer Probleme. Schreiben Sie eine rot-schwarz-Baum als eine Lernübung ist eine feine Idee, aber um wirklich etwas lernen, müssen Sie, um sicherzustellen, dass es ist 1) richtig und 2) einigermaßen idiomatischen C++. Das erstere ist schwer zu überprüfen, auf Ihre eigenen, und das zweite ist unmöglich. Was werden Sie tun, um sicherzustellen, dass Sie etwas lernen aus dieser übung?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wenn Sie müssen freigeben der alten Instanz und weiteres erstellen, sollten Sie zuerst sicherstellen, dass die Schaffung der neuen Sache gelingt:
Wenn Sie den Anruf löschen zuerst, und dann eine neue erstellen eine exception wirft, dann wird die Instanz der Klasse wird ein dangling pointer. E. g, wird Ihr Destruktor am Ende vielleicht bis löschen möchten Sie den Zeiger wieder (Undefiniertes Verhalten).
Könnte man auch vermeiden, dass durch die Einstellung der Zeiger auf NULL dazwischen, aber der obige Weg ist noch besser: wenn das zurücksetzen fehlschlägt, wird das Objekt behält seine ursprüngliche Wert.
Als die Frage im code Kommentar.
Wäre dies die richtige Sache zu tun. Es ist normale string-Zuweisung.
Wäre dies die Zuordnung von Zeigern und völlig falsch. Sie würde Auslaufen der string-Instanz, die zuvor gezeigt, durch
str
. Schlimmer noch, es ist sehr wahrscheinlich, dass der string an die Funktion übergeben ist nicht zugeordnet mitnew
im ersten Ort (sollten Sie sich nicht mischen Zeiger auf dynamisch reservierten und automatische Objekte). Darüber hinaus könnten Sie speichern die Adresse einer string-Objekt, dessen Lebensdauer endet mit dem Aufruf der Funktion (wenn die const-Referenz gebunden ist, um eine vorübergehende).Warum Sie denken, Sie brauchen, um zu speichern einen Zeiger auf einen string in Ihre Klasse? Zeiger auf C++ - Sammlungen wie "string" sind eigentlich sehr selten nötig. Die Klasse sollte fast sicher so Aussehen:
Nur pinpointing hier, aber
würde nicht kompiliert (die Sie versuchen zu ordnen _str, das ist der Wert, der ein string übergeben durch Verweis auf str, das ist die Adresse der Zeichenkette). Wenn Sie das tun wollten, würden Sie schreiben :
(und das hätte man ändern können _str oder str, so dass die constnest entspricht).
Aber dann, wie Sie Ihre intuition sagte Ihnen, Sie würden zugespielt haben, die Erinnerung an was auch immer string-Objekt wurde bereits gezeigt, durch str.
Wie bereits erwähnt, wenn Sie eine variable hinzufügen, um eine Klasse in C++, Sie müssen denken, ob die variable ist im Besitz des Objektes, oder durch etwas anderes.
Wenn es im Besitz des Objekt -, als Sie wahrscheinlich besser dran mit speichern Sie es als einen Wert und kopieren von Sachen um (aber dann müssen Sie sicherstellen, dass Kopien passieren nicht im Rücken).
Es ist nicht im Besitz, dann speichern Sie es als ein Zeiger, und Sie müssen nicht unbedingt kopiert werden muss, um die Dinge die ganze Zeit.
Anderen Menschen erklären das besser als ich, denn ich bin nicht wirklich komfortabel mit es.
Was ich am Ende tun eine Menge schreiben Sie code wie diesen :
Ist, dass, wenn ein Objekt hängt etwas in der 'Java' /'Ioc' Sinn (die Objekte, die anderswo existiert, sind Sie nicht erstellen Sie es, und Sie will nur das call-Methode), würde ich speichern, die Abhängigkeit als eine Referenz, mit dep_xxxx.
Wenn ich das Objekt erstellen, würde ich einen Zeiger, der mit einem Präfix p_.
Dies ist nur um den code mehr "sofort". Nicht sicher, ob es hilft.
Nur meine 2c.
Glück mit dem memory-mgt, du hast Recht, dass es ist der schwierige Teil kommen, von Java ; nicht mit dem schreiben von code, bis Sie sind komfortabel, oder du wirst Stunden damit verbringen, zu jagen segaults.
In der Hoffnung, das hilft !
Die Allgemeine Regel in C++ ist, dass für jedes Objekt erstellt mit "neu" muss es sein, eine "löschen". Um sicherzustellen, dass immer passiert, in der schwierige Teil ; -) Modernen C++ - Programmierer vermeiden Sie das erstellen von Speicher auf dem heap (also mit den "neuen") wie die Pest und verwenden von stack-Objekten statt. Wirklich überlegen Sie, ob Sie brauchen, um mit "neuen" in Ihrem code. Es ist nur selten erforderlich.
Wenn Sie aus einem hintergrund mit Müll gesammelt Sprachen und finden Sie selbst wirklich brauchen, um zu verwenden, heap-Speicher, schlage ich vor, den boost-shared-Pointer. Sie verwenden Sie wie folgt:
myPointer hat so ziemlich die gleiche Sprache Semantik als reguläre Zeiger, aber shared_ptr verwendet reference counting, um festzustellen, Wann ein Objekt löschen, es ist die Referenzierung. Es ist im Grunde tun sich die garbage-collection. Die docs sind hier: http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/smart_ptr.htm
Werde ich nur schreiben Klasse.
Für Klassen, die die Ressourcen enthalten, wie diese, die Kopie-Konstruktor, Zuweisungsoperator und Destruktor sind alle notwendig. Der schwierige Teil der copy-Konstruktor und Zuweisungs-operator ist, dass Sie brauchen, um zu löschen
Foo
genau einmal. Wenn der copy-Konstruktor-Initialisierung hatte, sagte:foo(a.foo)
, insbesondere dann, dassFoo
würde gelöscht, wenn das Objekt initialisiert wurde zerstört und einmal, wenn das Objekt initialisiert (a
) zerstört wurde.Die Klasse, die Art, wie ich geschrieben habe, es muss dokumentiert werden, wie die Eigenverantwortung der
Foo
pointer wird übergeben, weilFoo * f = new Foo(); A a(f); delete f;
wird auch dazu führen, doppelte löschen.Anderen Weg, das zu tun, wäre die Verwendung von Boost smart-Pointer (die waren der Kern der nächste standard ist smart Pointer) und haben
boost::shared_ptr<Foo> foo;
stattFoo * f;
in der definition der Klasse. In diesem Fall wird der copy Konstruktor sein sollteA(const A &a):foo(a.foo) {}
, da die smart-pointer kümmert löschen derFoo
wenn alle Kopien der shared pointer auf ihn hinweisen, sind zerstört. (Es gibt Probleme, man kann in hier auch, besonders wenn Sie mischenshared_ptr<>
s mit jeder anderen form der Zeiger, aber wenn man sich anshared_ptr<>
während Sie sollten OK sein.)Anmerkung: ich Schreibe dies, ohne läuft es durch einen compiler. Ich bin mit dem Ziel für Genauigkeit und gutem Stil (wie die Verwendung von Initialisierungen im Konstruktor). Wenn jemand ein problem findet, bitte kommentieren.
foo = foo_
im setFoo nicht funktioniert.foo
warFoo *
.Drei Kommentare:
Benötigen Sie einen Destruktor sowie.
Sie wirklich brauchen nicht zu verwenden heap-Speicher zugewiesen, in diesem Fall. Könnten Sie Folgendes tun:
Nicht die auskommentierte version. Das wäre ein memory leak. Java kümmert, weil es hat die garbage-collection. C++ verfügt nicht über diese Funktion.
Ja. Wenn es ein raw-pointer, müssen Sie löschen Sie das alte Objekt zunächst.
Gibt es smart-pointer-Klassen, die dies für Sie tun, wenn Sie einen neuen Wert zuweisen.