Heim  >  Artikel  >  Backend-Entwicklung  >  C++11 neue Funktionen für intelligente Zeiger (shared_ptr/unique_ptr/weak_ptr)

C++11 neue Funktionen für intelligente Zeiger (shared_ptr/unique_ptr/weak_ptr)

高洛峰
高洛峰Original
2017-01-23 14:00:531960Durchsuche

Grundlegende Verwendung von shared_ptr

shared_ptr verwendet die Referenzzählung, um das Objekt zu verwalten, auf das verwiesen wird. Wenn ein neuer shared_ptr vorhanden ist, der auf dasselbe Objekt zeigt (kopiert den shared_ptr usw.), wird der Referenzzähler um 1 erhöht. Wenn shared_ptr den Gültigkeitsbereich verlässt, wird der Referenzzähler um 1 verringert. Wenn der Referenzzähler 0 erreicht, wird der verwaltete Speicher freigegeben.

Der Vorteil davon ist, dass es Programmierern den Druck erspart, Speicher manuell freizugeben. In der Vergangenheit war es zur Behandlung von Ausnahmen im Programm häufig erforderlich, den Zeiger manuell in eine Klasse zu kapseln und den Destruktor zu verwenden, um den dynamisch zugewiesenen Speicher freizugeben. Jetzt kann dieser Prozess shared_ptr überlassen werden.

Im Allgemeinen verwenden wir make_shared, um shared_ptr zu erhalten.

cout<<"test shared_ptr base usage:"<<endl;
shared_ptr<string> p1 = make_shared<string>("");
if(p1 && p1->empty())
*p1 = "hello";
 
auto p2 = make_shared<string>("world");
cout<<*p1<<&#39; &#39;<<*p2<<endl;
 
cout<<"test shared_ptr use_count:"<<endl;
cout<<"p1 cnt:"<<p1.use_count()<<"\tp2 cnt:"<<p2.use_count()<<endl;
 
auto p3 = p2;
cout<<"p1 cnt:"<<p1.use_count()<<"\tp2 cnt:"<<p2.use_count()<<"\tp3 cnt:"<<p3.use_count()<<endl;
p2 = p1;
cout<<"p1 cnt:"<<p1.use_count()<<"\tp2 cnt:"<<p2.use_count()<<"\tp3 cnt:"<<p3.use_count()<<endl;

shared_ptr und new

shared_ptr können mithilfe eines Zeigers initialisiert werden, der von einem neuen Ausdruck zurückgegeben wird.

cout<<"test shared_ptr and new:"<<endl;
shared_ptr<int> p4(new int(1024));
//shared_ptr<int> p5 = new int(1024); // wrong, no implicit constructor
cout<<*p4<<endl;

Der von einem neuen Ausdruck zurückgegebene Zeiger kann jedoch nicht shared_ptr zugewiesen werden.

Außerdem sollte besonders darauf geachtet werden, new und shared_ptr nicht zu vermischen!

void process(shared_ptr<int> ptr)
{
cout<<"in process use_count:"<<ptr.use_count()<<endl;
}
 
cout<<"don&#39;t mix shared_ptr and normal pointer:"<<endl;
shared_ptr<int> p5(new int(1024));
process(p5);
int v5 = *p5;
cout<<"v5: "<<v5<<endl;
 
int *p6 = new int(1024);
process(shared_ptr<int>(p6));
int v6 = *p6;
cout<<"v6: "<<v6<<endl;

Das obige Programmfragment gibt Folgendes aus:

in Prozess use_count:2
v5: 1024
in Prozess use_count:1
v6: 0
Sie können sehen, dass, wenn Prozess p6 zum zweiten Mal verwendet wird, der Referenzzähler von shared_ptr ist 1. Beim Verlassen des Prozessbereichs wird der entsprechende Speicher freigegeben und p6 wird zu einem hängenden Zeiger.

Wenn also der von einem neuen Ausdruck zurückgegebene Zeiger von shared_ptr verwaltet wird, greifen Sie nicht über gewöhnliche Zeiger auf diesen Speicher zu!

shared_ptr.reset

shared_ptr kann über die Reset-Methode zurückgesetzt werden, um auf ein anderes Objekt zu verweisen. Zu diesem Zeitpunkt wird der Referenzzähler des ursprünglichen Objekts um eins reduziert.

cout<<"test shared_ptr reset:"<<endl;
cout<<"p1 cnt:"<<p1.use_count()<<"\tp2 cnt:"<<p2.use_count()<<"\tp3 nt:"<<p3.use_count()<<endl;
p1.reset(new string("cpp11"));
cout<<"p1 cnt:"<<p1.use_count()<<"\tp2 cnt:"<<p2.use_count()<<"\tp3 cnt:"<<p3.use_count()<<endl;
shared_ptr deleter

Sie können eine Löschfunktion anpassen, die aufgerufen wird, wenn shared_ptr das Objekt freigibt.

void print_at_delete(int *p)
{
cout<<"deleting..."<<p<<&#39;\t&#39;<<*p<<endl;
delete p;
}
 
cout<<"test shared_ptr deleter:"<<endl;
int *p7 = new int(1024);
shared_ptr<int> p8(p7, print_at_delete);
p8 = make_shared<int>(1025);

unique_ptr Grundlegende Verwendung

unique_ptr gilt ausschließlich für das Objekt, auf das gezeigt wird, wie der Name schon sagt. Daher kann unique_ptr nicht kopiert, zugewiesen usw. werden, die Steuerung kann jedoch über die Release-Funktion zwischen unique_ptr übertragen werden.

cout<<"test unique_ptr base usage:"<<endl;
unique_ptr<int> up1(new int(1024));
cout<<"up1: "<<*up1<<endl;
unique_ptr<int> up2(up1.release());
cout<<"up2: "<<*up2<<endl;
//unique_ptr<int> up3(up1); // wrong, unique_ptr can not copy
//up2 = up1; // wrong, unique_ptr can not copy
unique_ptr<int> up4(new int(1025));
up4.reset(up2.release());
cout<<"up4: "<<*up4<<endl;

unique_ptr als Parameter und Rückgabewert

Für die oben genannten Einschränkungen beim Kopieren gibt es zwei Sonderfälle, d. h. unique_ptr kann als Funktion verwendet werden. Der Rückgabewert und die Parameter werden verwendet. Obwohl es derzeit eine implizite Kopie gibt, ist dies nicht undurchführbar.

unique_ptr<int> clone(int p)
{
return unique_ptr<int>(new int(p));
}
 
void process_unique_ptr(unique_ptr<int> up)
{
cout<<"process unique ptr: "<<*up<<endl;
}
 
cout<<"test unique_ptr parameter and return value:"<<endl;
auto up5 = clone(1024);
cout<<"up5: "<<*up5<<endl;
process_unique_ptr(move(up5));
//cout<<"up5 after process: "<<*up5<<endl; // would cause segmentfault

Die std::move-Funktion hier wird später ausführlich besprochen^_^

unique_ptr deleter

unique_ptr kann im Gegensatz zu shared_ptr auch den Löschertyp im Vorlagenparameter angeben. Glücklicherweise haben wir das leistungsstarke Tool decltype, sonst wäre das Schreiben mühsam.

cout<<"test unique_ptr deleter:"<<endl;
int *p9 = new int(1024);
unique_ptr<int, decltype(print_at_delete) *> up6(p9, print_at_delete);
unique_ptr<int> up7(new int(1025));
up6.reset(up7.release());

weak_ptr

weak_ptr wird im Allgemeinen in Verbindung mit shared_ptr verwendet. Es kann auf das Objekt verweisen, auf das shared_ptr zeigt, erhöht jedoch nicht den Referenzzähler des Objekts. Auf diese Weise ist es möglich, dass das Objekt, auf das schwach_ptr zeigt, tatsächlich freigegeben wurde. Daher verfügt schwacher_ptr über eine Sperrfunktion, die versucht, einen shared_ptr abzurufen, der auf das Objekt zeigt.

cout<<"test weak_ptr basic usage:"<<endl;
auto p10 = make_shared<int>(1024);
weak_ptr<int> wp1(p10);
cout<<"p10 use_count: "<<p10.use_count()<<endl;
//p10.reset(new int(1025)); // this will cause wp1.lock() return a false obj
shared_ptr<int> p11 = wp1.lock();
if(p11) cout<<"wp1: "<<*p11<<" use count: "<<p11.use_count()<<endl;

Zusammenfassung

shared_ptr verwendet die Referenzzählung, um das Objekt zu verwalten, auf das gezeigt wird.
Shared_ptr kann mit einem Zeiger initialisiert werden, der von einem neuen Ausdruck zurückgegeben wird. Ein von einem neuen Ausdruck zurückgegebener Zeiger kann jedoch nicht shared_ptr zugewiesen werden.
Sobald der von einem neuen Ausdruck zurückgegebene Zeiger von shared_ptr verwaltet wird, greifen Sie nicht über normale Zeiger auf diesen Speicher zu.
shared_ptr kann über die Reset-Methode zurückgesetzt werden, um auf ein anderes Objekt zu verweisen. Zu diesem Zeitpunkt wird der Referenzzähler des ursprünglichen Objekts um eins verringert.
Sie können eine Löschfunktion anpassen, die aufgerufen wird, wenn shared_ptr das Objekt freigibt.
unique_ptr ist exklusiv für das Objekt, auf das gezeigt wird.
Unique_ptr kann nicht kopiert, zugewiesen usw. werden, die Steuerung kann jedoch über die Release-Funktion zwischen unique_ptr übertragen werden.
unique_ptr kann als Rückgabewert und Parameter der Funktion verwendet werden.
unique_ptr kann auch einen Löscher festlegen, und der Typ des Löschers muss in den Vorlagenparametern angegeben werden.
Weak_ptr wird im Allgemeinen in Verbindung mit shared_ptr verwendet. Es kann auf das Objekt verweisen, auf das shared_ptr zeigt, erhöht jedoch nicht den Referenzzähler des Objekts.
Weak_ptr verfügt über eine Sperrfunktion, die versucht, einen shared_ptr abzurufen, der auf das Objekt zeigt.

Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass er zum Lernen aller beiträgt. Ich hoffe auch, dass jeder die PHP-Chinesisch-Website unterstützt.

Weitere Artikel zu den neuen Funktionen von C++ 11, Smart Pointern (shared_ptr/unique_ptr/weak_ptr), finden Sie auf der chinesischen PHP-Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn