Ich habe angefangen, intelligente Zeiger von C ++ 11 zu studieren, und sehe keine nützliche Verwendung von std::weak_ptr
. Kann mir jemand sagen, wann std::weak_ptr
es nützlich / notwendig ist?
Ich habe angefangen, intelligente Zeiger von C ++ 11 zu studieren, und sehe keine nützliche Verwendung von std::weak_ptr
. Kann mir jemand sagen, wann std::weak_ptr
es nützlich / notwendig ist?
Antworten:
Ein gutes Beispiel wäre ein Cache.
Für Objekte, auf die kürzlich zugegriffen wurde, möchten Sie sie im Speicher behalten, sodass Sie einen starken Zeiger auf sie halten. In regelmäßigen Abständen scannen Sie den Cache und entscheiden, auf welche Objekte in letzter Zeit nicht zugegriffen wurde. Sie müssen diese nicht im Speicher behalten, damit Sie den starken Zeiger loswerden.
Aber was ist, wenn dieses Objekt verwendet wird und ein anderer Code einen starken Zeiger darauf enthält? Wenn der Cache seinen einzigen Zeiger auf das Objekt entfernt, kann er ihn nie wieder finden. Der Cache behält also einen schwachen Zeiger auf Objekte bei, die er finden muss, wenn sie zufällig im Speicher bleiben.
Dies ist genau das, was ein schwacher Zeiger tut - er ermöglicht es Ihnen, ein Objekt zu lokalisieren, wenn es noch vorhanden ist, behält es jedoch nicht bei, wenn nichts anderes es benötigt.
std::weak_ptr
ist ein sehr guter Weg, um das Problem der baumelnden Zeiger zu lösen. Durch die Verwendung von Rohzeigern kann nicht festgestellt werden, ob die referenzierten Daten freigegeben wurden oder nicht. Stattdessen können die Benutzer die Gültigkeit der Daten durch Aufrufen von oder überprüfen , indem sie std::shared_ptr
die Daten verwalten lassen und std::weak_ptr
den Benutzern die Daten zur Verfügung stellen .expired()
lock()
Sie können dies nicht std::shared_ptr
alleine tun , da alle std::shared_ptr
Instanzen das Eigentum an den Daten teilen, die nicht entfernt werden, bevor alle Instanzen von std::shared_ptr
entfernt wurden. Hier ist ein Beispiel für die Überprüfung auf baumelnden Zeiger mithilfe von lock()
:
#include <iostream>
#include <memory>
int main()
{
// OLD, problem with dangling pointer
// PROBLEM: ref will point to undefined data!
int* ptr = new int(10);
int* ref = ptr;
delete ptr;
// NEW
// SOLUTION: check expired() or lock() to determine if pointer is valid
// empty definition
std::shared_ptr<int> sptr;
// takes ownership of pointer
sptr.reset(new int);
*sptr = 10;
// get pointer to data without taking ownership
std::weak_ptr<int> weak1 = sptr;
// deletes managed object, acquires new pointer
sptr.reset(new int);
*sptr = 5;
// get pointer to new data without taking ownership
std::weak_ptr<int> weak2 = sptr;
// weak1 is expired!
if(auto tmp = weak1.lock())
std::cout << *tmp << '\n';
else
std::cout << "weak1 is expired\n";
// weak2 points to new data (5)
if(auto tmp = weak2.lock())
std::cout << *tmp << '\n';
else
std::cout << "weak2 is expired\n";
}
std::weak_ptr::lock
Erstellt eine neue std::shared_ptr
, die das Eigentum an dem verwalteten Objekt teilt.
Eine andere Antwort, hoffentlich einfacher. (für andere Googler)
Angenommen, Sie haben Team
und Member
Objekte.
Offensichtlich ist es eine Beziehung: Das Team
Objekt hat Zeiger auf seine Members
. Und es ist wahrscheinlich, dass die Mitglieder auch einen Rückzeiger auf ihr Team
Objekt haben.
Dann haben Sie einen Abhängigkeitszyklus. Wenn Sie verwenden shared_ptr
, werden Objekte nicht mehr automatisch freigegeben, wenn Sie die Referenz auf sie aufgeben, da sie zyklisch aufeinander verweisen. Dies ist ein Speicherverlust.
Sie brechen dies mit weak_ptr
. Der "Eigentümer" verwendet normalerweise shared_ptr
und der "Eigentümer" verwendet a weak_ptr
für sein übergeordnetes Element und konvertiert es vorübergehend in, shared_ptr
wenn er Zugriff auf sein übergeordnetes Element benötigt.
Speichern Sie einen schwachen ptr:
weak_ptr<Parent> parentWeakPtr_ = parentSharedPtr; // automatic conversion to weak from shared
Verwenden Sie es dann bei Bedarf
shared_ptr<Parent> tempParentSharedPtr = parentWeakPtr_.lock(); // on the stack, from the weak ptr
if( !tempParentSharedPtr ) {
// yes, it may fail if the parent was freed since we stored weak_ptr
} else {
// do stuff
}
// tempParentSharedPtr is released when it goes out of scope
shared_ptr
ist, das Eigentum zu teilen, damit niemand die besondere Verantwortung hat, den Speicher freizugeben. Er wird automatisch freigegeben, wenn er nicht mehr verwendet wird. Es sei denn, es gibt eine Schleife ... Möglicherweise haben mehrere Teams denselben Spieler (frühere Teams?). Wenn das Teamobjekt die Mitglieder "besitzt", muss zunächst kein a verwendet werden shared_ptr
.
shared_ptr
von seinen "Teammitgliedern" referenziert wird, wann wird es zerstört? Was Sie beschreiben, ist ein Fall, in dem es keine Schleife gibt.
Hier ist ein Beispiel, das mir von @jleahy gegeben wurde: Angenommen, Sie haben eine Sammlung von Aufgaben, die asynchron ausgeführt und von einem verwaltet werden std::shared_ptr<Task>
. Möglicherweise möchten Sie in regelmäßigen Abständen etwas mit diesen Aufgaben tun, sodass ein Timer-Ereignis möglicherweise a durchläuft std::vector<std::weak_ptr<Task>>
und den Aufgaben etwas zu tun gibt. Gleichzeitig kann eine Aufgabe gleichzeitig entschieden haben, dass sie nicht mehr benötigt wird, und sterben. Der Timer kann somit prüfen, ob die Aufgabe noch aktiv ist, indem er aus dem schwachen Zeiger einen gemeinsamen Zeiger erstellt und diesen gemeinsamen Zeiger verwendet, sofern er nicht null ist.
Sie sind bei Boost.Asio nützlich, wenn Sie nicht garantiert sind, dass ein Zielobjekt noch vorhanden ist, wenn ein asynchroner Handler aufgerufen wird. Der Trick besteht darin, ein weak_ptr
Objekt mit std::bind
oder Lambda-Captures in das asynchrone Handler-Objekt einzubinden .
void MyClass::startTimer()
{
std::weak_ptr<MyClass> weak = shared_from_this();
timer_.async_wait( [weak](const boost::system::error_code& ec)
{
auto self = weak.lock();
if (self)
{
self->handleTimeout();
}
else
{
std::cout << "Target object no longer exists!\n";
}
} );
}
Dies ist eine Variante der self = shared_from_this()
Redewendung, die häufig in Boost.Asio-Beispielen verwendet wird, bei denen ein ausstehender asynchroner Handler die Lebensdauer des Zielobjekts nicht verlängert, jedoch dennoch sicher ist, wenn das Zielobjekt gelöscht wird.
this
self = shared_from_this()
Idioms, wenn der Handler Methoden innerhalb derselben Klasse aufruft.
shared_ptr : enthält das reale Objekt.
schwach_ptr : Wird verwendet lock
, um eine Verbindung zum tatsächlichen Eigentümer herzustellen, oder gibt shared_ptr
andernfalls einen NULL- Wert zurück .
Grob gesagt weak_ptr
ähnelt die Rolle der Rolle der Wohnungsagentur . Ohne Agenten müssen wir möglicherweise zufällige Häuser in der Stadt überprüfen, um ein Haus zur Miete zu bekommen. Die Makler stellen sicher, dass wir nur die Häuser besuchen, die noch zugänglich und zu vermieten sind.
weak_ptr
Es ist auch gut, das korrekte Löschen eines Objekts zu überprüfen - insbesondere bei Komponententests. Ein typischer Anwendungsfall könnte folgendermaßen aussehen:
std::weak_ptr<X> weak_x{ shared_x };
shared_x.reset();
BOOST_CHECK(weak_x.lock());
... //do something that should remove all other copies of shared_x and hence destroy x
BOOST_CHECK(!weak_x.lock());
Bei der Verwendung von Zeigern ist es wichtig, die verschiedenen verfügbaren Zeigertypen zu verstehen und zu wissen, wann es sinnvoll ist, die einzelnen Zeiger zu verwenden. Es gibt vier Arten von Zeigern in zwei Kategorien:
SomeClass* ptrToSomeClass = new SomeClass();
]std::unique_ptr<SomeClass> uniquePtrToSomeClass ( new SomeClass() );
std::shared_ptr<SomeClass> sharedPtrToSomeClass ( new SomeClass() );
std::weak_ptr<SomeClass> weakPtrToSomeWeakOrSharedPtr ( weakOrSharedPtr );
Raw-Zeiger (manchmal als "Legacy-Zeiger" oder "C-Zeiger" bezeichnet) bieten ein "Bare-Bones" -Zeigerverhalten und sind eine häufige Ursache für Fehler und Speicherlecks. Raw-Zeiger bieten keine Möglichkeit, den Besitz der Ressource zu verfolgen, und Entwickler müssen 'delete' manuell aufrufen, um sicherzustellen, dass sie keinen Speicherverlust verursachen. Dies wird schwierig, wenn die Ressource gemeinsam genutzt wird, da es schwierig sein kann zu wissen, ob noch Objekte auf die Ressource zeigen. Aus diesen Gründen sollten Rohzeiger generell vermieden und nur in leistungskritischen Abschnitten des Codes mit begrenztem Umfang verwendet werden.
Eindeutige Zeiger sind ein grundlegender intelligenter Zeiger, der den zugrunde liegenden Rohzeiger auf die Ressource "besitzt" und für das Aufrufen "Löschen" und das Freigeben des zugewiesenen Speichers verantwortlich ist, sobald das Objekt, dem der eindeutige Zeiger "gehört", den Gültigkeitsbereich verlässt. Der Name "eindeutig" bezieht sich auf die Tatsache, dass nur ein Objekt den eindeutigen Zeiger zu einem bestimmten Zeitpunkt "besitzen" darf. Das Eigentum kann über den Befehl move auf ein anderes Objekt übertragen werden, ein eindeutiger Zeiger kann jedoch niemals kopiert oder freigegeben werden. Aus diesen Gründen sind eindeutige Zeiger eine gute Alternative zu Rohzeigern, wenn zu einem bestimmten Zeitpunkt nur ein Objekt den Zeiger benötigt, und dies entlastet den Entwickler von der Notwendigkeit, am Ende des Lebenszyklus des besitzenden Objekts Speicher freizugeben.
Freigegebene Zeiger sind eine andere Art von intelligenten Zeigern, die eindeutigen Zeigern ähneln, jedoch ermöglichen, dass viele Objekte Eigentümer des gemeinsam genutzten Zeigers sind. Wie ein eindeutiger Zeiger sind gemeinsam genutzte Zeiger dafür verantwortlich, den zugewiesenen Speicher freizugeben, sobald alle Objekte auf die Ressource zeigen. Dies wird mit einer Technik erreicht, die als Referenzzählung bezeichnet wird. Jedes Mal, wenn ein neues Objekt den gemeinsamen Zeiger in Besitz nimmt, wird der Referenzzähler um eins erhöht. Wenn ein Objekt den Gültigkeitsbereich verlässt oder nicht mehr auf die Ressource zeigt, wird der Referenzzähler um eins verringert. Wenn der Referenzzähler Null erreicht, wird der zugewiesene Speicher freigegeben. Aus diesen Gründen sind gemeinsam genutzte Zeiger eine sehr leistungsstarke Art von intelligenten Zeigern, die immer dann verwendet werden sollten, wenn mehrere Objekte auf dieselbe Ressource verweisen müssen.
Schließlich sind schwache Zeiger eine andere Art von intelligentem Zeiger, der nicht direkt auf eine Ressource zeigt, sondern auf einen anderen Zeiger (schwach oder gemeinsam genutzt). Schwache Zeiger können nicht direkt auf ein Objekt zugreifen, aber sie können erkennen, ob das Objekt noch vorhanden ist oder ob es abgelaufen ist. Ein schwacher Zeiger kann vorübergehend in einen gemeinsam genutzten Zeiger konvertiert werden, um auf das Objekt zuzugreifen, auf das verwiesen wird (sofern es noch vorhanden ist). Betrachten Sie zur Veranschaulichung das folgende Beispiel:
In diesem Beispiel haben Sie einen schwachen Zeiger auf Besprechung B. Sie sind kein "Eigentümer" in Besprechung B, sodass diese ohne Sie enden kann, und Sie wissen nicht, ob sie beendet wurde oder nicht, es sei denn, Sie überprüfen. Wenn es nicht beendet ist, können Sie beitreten und teilnehmen, andernfalls können Sie nicht. Dies unterscheidet sich von einem gemeinsamen Zeiger auf Besprechung B, da Sie dann sowohl in Besprechung A als auch in Besprechung B ein "Eigentümer" sind (an beiden gleichzeitig teilnehmen).
Das Beispiel zeigt, wie ein schwacher Zeiger funktioniert und nützlich ist, wenn ein Objekt ein externer Beobachter sein muss , aber nicht die Verantwortung für die gemeinsame Nutzung des Eigentums übernehmen möchte. Dies ist besonders nützlich in dem Szenario, in dem zwei Objekte aufeinander zeigen müssen (auch als Zirkelverweis bezeichnet). Mit gemeinsam genutzten Zeigern kann kein Objekt freigegeben werden, da das andere Objekt immer noch stark auf sie zeigt. Wenn einer der Zeiger ein schwacher Zeiger ist, kann das Objekt, das den schwachen Zeiger enthält, bei Bedarf weiterhin auf das andere Objekt zugreifen, sofern es noch vorhanden ist.
Abgesehen von den anderen bereits erwähnten gültigen Anwendungsfällen std::weak_ptr
ist ein großartiges Tool in einer Multithread-Umgebung, weil
std::shared_ptr
in Verbindung mit std::weak_ptr
ist sicher gegen baumelnde Zeiger - im Gegensatz zu std::unique_ptr
in Verbindung mit rohen Zeigernstd::weak_ptr::lock()
ist eine atomare Operation (siehe auch Informationen zur Thread-Sicherheit von schwachem_ptr )Stellen Sie sich eine Aufgabe vor, um alle Bilder eines Verzeichnisses (~ 10.000) gleichzeitig in den Speicher zu laden (z. B. als Miniaturbild-Cache). Offensichtlich ist der beste Weg, dies zu tun, ein Steuerelement-Thread, der die Bilder verarbeitet und verwaltet, und mehrere Worker-Threads, die die Bilder laden. Das ist eine leichte Aufgabe. Hier ist eine sehr vereinfachte Implementierung ( join()
usw. wird weggelassen, die Threads müssten in einer realen Implementierung usw. anders behandelt werden)
// a simplified class to hold the thumbnail and data
struct ImageData {
std::string path;
std::unique_ptr<YourFavoriteImageLibData> image;
};
// a simplified reader fn
void read( std::vector<std::shared_ptr<ImageData>> imagesToLoad ) {
for( auto& imageData : imagesToLoad )
imageData->image = YourFavoriteImageLib::load( imageData->path );
}
// a simplified manager
class Manager {
std::vector<std::shared_ptr<ImageData>> m_imageDatas;
std::vector<std::unique_ptr<std::thread>> m_threads;
public:
void load( const std::string& folderPath ) {
std::vector<std::string> imagePaths = readFolder( folderPath );
m_imageDatas = createImageDatas( imagePaths );
const unsigned numThreads = std::thread::hardware_concurrency();
std::vector<std::vector<std::shared_ptr<ImageData>>> splitDatas =
splitImageDatas( m_imageDatas, numThreads );
for( auto& dataRangeToLoad : splitDatas )
m_threads.push_back( std::make_unique<std::thread>(read, dataRangeToLoad) );
}
};
Es wird jedoch viel komplizierter, wenn Sie das Laden der Bilder unterbrechen möchten, z. B. weil der Benutzer ein anderes Verzeichnis ausgewählt hat. Oder auch wenn Sie den Manager zerstören wollen.
Sie benötigen eine Thread-Kommunikation und müssen alle Loader-Threads stoppen, bevor Sie Ihr m_imageDatas
Feld ändern können . Andernfalls würden die Lader so lange geladen, bis alle Bilder fertig sind - auch wenn sie bereits veraltet sind. Im vereinfachten Beispiel wäre das nicht allzu schwierig, aber in einer realen Umgebung können die Dinge viel komplizierter sein.
Die Threads wären wahrscheinlich Teil eines Thread-Pools, der von mehreren Managern verwendet wird, von denen einige gestoppt werden und andere nicht usw. Der einfache Parameter imagesToLoad
wäre eine gesperrte Warteschlange, in die diese Manager ihre Image-Anforderungen von verschiedenen Steuer-Threads verschieben mit den Lesern, die die Anfragen - in beliebiger Reihenfolge - am anderen Ende platzieren. Und so wird die Kommunikation schwierig, langsam und fehleranfällig. Eine sehr elegante Möglichkeit, in solchen Fällen zusätzliche Kommunikation zu vermeiden, ist die Verwendung std::shared_ptr
in Verbindung mit std::weak_ptr
.
// a simplified reader fn
void read( std::vector<std::weak_ptr<ImageData>> imagesToLoad ) {
for( auto& imageDataWeak : imagesToLoad ) {
std::shared_ptr<ImageData> imageData = imageDataWeak.lock();
if( !imageData )
continue;
imageData->image = YourFavoriteImageLib::load( imageData->path );
}
}
// a simplified manager
class Manager {
std::vector<std::shared_ptr<ImageData>> m_imageDatas;
std::vector<std::unique_ptr<std::thread>> m_threads;
public:
void load( const std::string& folderPath ) {
std::vector<std::string> imagePaths = readFolder( folderPath );
m_imageDatas = createImageDatas( imagePaths );
const unsigned numThreads = std::thread::hardware_concurrency();
std::vector<std::vector<std::weak_ptr<ImageData>>> splitDatas =
splitImageDatasToWeak( m_imageDatas, numThreads );
for( auto& dataRangeToLoad : splitDatas )
m_threads.push_back( std::make_unique<std::thread>(read, dataRangeToLoad) );
}
};
Diese Implementierung ist fast so einfach wie die erste, benötigt keine zusätzliche Thread-Kommunikation und kann Teil eines Thread-Pools / einer Thread-Warteschlange in einer realen Implementierung sein. Da die abgelaufenen Bilder übersprungen und nicht abgelaufene Bilder verarbeitet werden, müssten die Threads während des normalen Betriebs niemals gestoppt werden. Sie können den Pfad jederzeit sicher ändern oder Ihre Manager zerstören, da der Leser fn prüft, ob der Besitzzeiger nicht abgelaufen ist.
http://en.cppreference.com/w/cpp/memory/weak_ptr std :: schwach_ptr ist ein intelligenter Zeiger, der einen nicht besitzenden ("schwachen") Verweis auf ein Objekt enthält, das von std :: shared_ptr verwaltet wird. Es muss in std :: shared_ptr konvertiert werden, um auf das referenzierte Objekt zugreifen zu können.
std :: schwach_ptr modelliert temporären Besitz: Wenn auf ein Objekt nur zugegriffen werden muss, wenn es vorhanden ist, und es jederzeit von einer anderen Person gelöscht werden kann, wird std :: schwach_ptr verwendet, um das Objekt zu verfolgen, und es wird in std konvertiert: : shared_ptr, um temporären Besitz zu übernehmen. Wenn das ursprüngliche std :: shared_ptr zu diesem Zeitpunkt zerstört wird, verlängert sich die Lebensdauer des Objekts, bis auch das temporäre std :: shared_ptr zerstört wird.
Darüber hinaus wird std :: schwach_ptr verwendet, um Zirkelverweise von std :: shared_ptr zu brechen.
Der gemeinsame Zeiger hat einen Nachteil: shared_pointer kann die Eltern-Kind-Zyklusabhängigkeit nicht verarbeiten. Bedeutet, wenn die übergeordnete Klasse das Objekt der untergeordneten Klasse mithilfe eines gemeinsam genutzten Zeigers verwendet, in derselben Datei, wenn die untergeordnete Klasse das Objekt der übergeordneten Klasse verwendet. Der gemeinsam genutzte Zeiger kann nicht alle Objekte zerstören, selbst der gemeinsam genutzte Zeiger ruft den Destruktor im Zyklusabhängigkeitsszenario überhaupt nicht auf. Grundsätzlich unterstützt der gemeinsam genutzte Zeiger den Referenzzählmechanismus nicht.
Diesen Nachteil können wir mit schwachem Zeiger überwinden.
weak_ptr
Umgang mit einer zirkulären Abhängigkeit ohne Änderung der Programmlogik als Drop-In-Ersatz für shared_ptr
?" :-)
Wenn wir das Objekt nicht besitzen wollen:
Ex:
class A
{
shared_ptr<int> sPtr1;
weak_ptr<int> wPtr1;
}
In der obigen Klasse besitzt wPtr1 nicht die Ressource, auf die wPtr1 zeigt. Wenn die Ressource gelöscht wurde, ist wPtr1 abgelaufen.
So vermeiden Sie zirkuläre Abhängigkeiten:
shard_ptr<A> <----| shared_ptr<B> <------
^ | ^ |
| | | |
| | | |
| | | |
| | | |
class A | class B |
| | | |
| ------------ |
| |
-------------------------------------
Wenn wir nun den shared_ptr der Klassen B und A erstellen, beträgt der use_count der beiden Zeiger zwei.
Wenn der shared_ptr den Gültigkeitsbereich verlässt, bleibt die Anzahl weiterhin 1, und daher werden die Objekte A und B nicht gelöscht.
class B;
class A
{
shared_ptr<B> sP1; // use weak_ptr instead to avoid CD
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
void setShared(shared_ptr<B>& p)
{
sP1 = p;
}
};
class B
{
shared_ptr<A> sP1;
public:
B() { cout << "B()" << endl; }
~B() { cout << "~B()" << endl; }
void setShared(shared_ptr<A>& p)
{
sP1 = p;
}
};
int main()
{
shared_ptr<A> aPtr(new A);
shared_ptr<B> bPtr(new B);
aPtr->setShared(bPtr);
bPtr->setShared(aPtr);
return 0;
}
Ausgabe:
A()
B()
Wie wir an der Ausgabe sehen können, werden A- und B-Zeiger niemals gelöscht und daher Speicher verloren.
Um solche Probleme zu vermeiden, verwenden Sie einfach schwaches_ptr in Klasse A anstelle von geteiltem_ptr, was sinnvoller ist.
Ich sehe std::weak_ptr<T>
als Griff zu a std::shared_ptr<T>
: Es ermöglicht mir, das zu bekommen, std::shared_ptr<T>
wenn es noch existiert, aber es wird seine Lebensdauer nicht verlängern. Es gibt verschiedene Szenarien, in denen eine solche Sichtweise nützlich ist:
// Some sort of image; very expensive to create.
std::shared_ptr< Texture > texture;
// A Widget should be able to quickly get a handle to a Texture. On the
// other hand, I don't want to keep Textures around just because a widget
// may need it.
struct Widget {
std::weak_ptr< Texture > texture_handle;
void render() {
if (auto texture = texture_handle.get(); texture) {
// do stuff with texture. Warning: `texture`
// is now extending the lifetime because it
// is a std::shared_ptr< Texture >.
} else {
// gracefully degrade; there's no texture.
}
}
};
Ein weiteres wichtiges Szenario besteht darin, Zyklen in Datenstrukturen zu unterbrechen.
// Asking for trouble because a node owns the next node, and the next node owns
// the previous node: memory leak; no destructors automatically called.
struct Node {
std::shared_ptr< Node > next;
std::shared_ptr< Node > prev;
};
// Asking for trouble because a parent owns its children and children own their
// parents: memory leak; no destructors automatically called.
struct Node {
std::shared_ptr< Node > parent;
std::shared_ptr< Node > left_child;
std::shared_ptr< Node > right_child;
};
// Better: break dependencies using a std::weak_ptr (but not best way to do it;
// see Herb Sutter's talk).
struct Node {
std::shared_ptr< Node > next;
std::weak_ptr< Node > prev;
};
// Better: break dependencies using a std::weak_ptr (but not best way to do it;
// see Herb Sutter's talk).
struct Node {
std::weak_ptr< Node > parent;
std::shared_ptr< Node > left_child;
std::shared_ptr< Node > right_child;
};
Herb Sutter hat ein ausgezeichnetes Gespräch , in dem die beste Verwendung von Sprachfunktionen (in diesem Fall intelligente Zeiger) zur Gewährleistung der standardmäßigen Leckfreiheit erklärt wird (was bedeutet: Alles klickt durch die Konstruktion an Ort und Stelle; Sie können es kaum vermasseln). Es ist ein Muss.