2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Nachteile von Rohzeigern:
delete
Geben Sie Ressourcen frei, was zu einem Ressourcenverlust führtdelete
Das Programm wurde zuvor normal beendet (z. B. wennif
Mittereturn
) oder abnormal beenden, bevor es zu spät istdelete
, was zu einem Ressourcenverlust führtZu diesem Zeitpunkt sind intelligente Hinweise erforderlich. Die Intelligenz intelligenter Zeiger spiegelt sich hauptsächlich in der Tatsache wider, dass Benutzer nicht auf die Freigabe von Ressourcen achten müssen, da intelligente Zeiger Ihnen dabei helfen, die Freigabe von Ressourcen vollständig zu verwalten. Dies stellt sicher, dass die Programmlogik unabhängig davon ausgeführt wird , wird es normal ausgeführt oder es werden Ausnahmen generiert.Wenn Ressourcen ablaufen (Funktionsumfang oder Programmende), werden sie freigegeben.
Lassen Sie uns selbst einen einfachen Smart Pointer implementieren
template<typename T>
class CSmartPtr
{
public:
CSmartPtr(T* ptr = nullptr) : mptr(ptr) {}
~CSmartPtr() { delete mptr; }
private:
T* mptr;
};
int main()
{
CSmartPtr<int> ptr(new int());
/*其它的代码...*/
/*
由于ptr是栈上的智能指针对象,不管是函数正常执行完,
还是运行过程中出现异常,栈上的对象都会自动调用析构函数,
在析构函数中进行了delete操作,保证释放资源
*/
return 0;
}
Aufgrund der oben genannten Eigenschaften werden intelligente Zeiger daher im Allgemeinen auf dem Stapel definiert. gleichzeitig,Ein Smart Pointer ist ein Klassenobjekt , wird im Konstruktor dieser Klasse ein Zeiger übergeben und der übergebene Zeiger im Destruktor freigegeben.Da dieser Objekttyp auf dem Stapel zugewiesen und freigegeben wird, wird er automatisch freigegeben, wenn unsere Funktion (oder unser Programm) endet.
Können also intelligente Zeiger auf dem Heap definiert werden?Zum BeispielCSmartPtr* p = new CSmartPtr(new int);
, die Kompilierung kann bestehen, aber die Definition hierp
Obwohl es sich um einen intelligenten Zeigertyp handelt, handelt es sich im Wesentlichen um einen Rohzeigerp
Muss es immer noch manuell machendelete
, es ist wieder das Problem, mit dem wir am Anfang mit bloßen Zeigern konfrontiert waren, also verwenden Sie es nicht so
Natürlich müssen intelligente Zeiger Rohzeigern ähnlich sein und auch gemeinsame Merkmale von Rohzeigern bieten.*
Und->
Die überladenen Funktionen der beiden Operatoren sind bei Verwendung tatsächlich dieselben wie Rohzeiger. Der Code lautet wie folgt:
template<typename T>
class CSmartPtr
{
public:
CSmartPtr(T* ptr = nullptr) : mptr(ptr) {}
~CSmartPtr() { delete mptr; }
T& operator*() { return *mptr; }
T* operator->() { return mptr; }
private:
T* mptr;
};
int main()
{
CSmartPtr<int> ptr(new int());
*ptr = 20; // operator*()一定要返回引用,这样才可以赋值
cout << *ptr << endl; // 20
class Test
{
public:
void test() { cout << "call Test::test()" << endl; }
};
CSmartPtr<Test> ptr2 = new Test();
(*ptr2).test(); // (*ptr2)取出Test对象,用对象调用方法
// operator->()返回的是一个指针,实现了用指针调用函数
// 即(ptr2.operator->()) -> test()
ptr2->test();
return 0;
}
Der im vorherigen Abschnitt implementierte Smart Pointer ist einem gewöhnlichen Rohzeiger sehr ähnlich, weist jedoch immer noch große Probleme auf. Siehe den folgenden Code:
CSmartPtr<int> p1(new int());
CSmartPtr<int> p2(p1); // 拷贝构造
Der laufende Code stürzt direkt ab, da der Standardkopierkonstruktor eine flache Kopie durchführt.p1
Undp2
gilt das Gleichenew int
Ressource,p2
Die Zerstörung gibt dann zunächst die Ressourcen freip1
Wenn es zerstört wird, wird esdelete
Wilder Zeiger, Programm stürzt ab
Wie können also die durch flache Kopien verursachten Probleme gelöst werden?umschreibenCSmartPtr
Schauen Sie sich den Kopierkonstruktor an
CSmartPtr(const CSmartPtr<T>& src) { mptr = new T(*src.mptr); }
Jetzt läuft der Code jedoch an dieser Stelle normalp1
Undp2
Es werden zwei unterschiedliche Ressourcen verwaltet. Wenn Benutzer sie nicht verstehen, denken sie fälschlicherweisep1
Undp2
Verwalten Sie dieselbe Ressource
Daher ist es falsch, den Kopierkonstruktor so zu schreiben
Wie kann man also das Problem der flachen Kopie intelligenter Zeiger lösen? Zwei Methoden:Intelligente Zeiger ohne Referenzzählung, intelligente Zeiger mit Referenzzählung
Schauen wir uns zunächst diesen Abschnitt anIntelligente Zeiger ohne Referenzzählung
auto_ptr
(C++98, jetzt veraltet)scoped_ptr
(Boost-Bibliothek)unique_ptr
(C++11, empfohlen)Schließen Sie die Header-Datei ein, wenn Sie Folgendes verwenden:#include <memory>
Betrachten wir zunächst diesen Code
auto_ptr<int> ptr1(new int());
auto_ptr<int> ptr2(ptr1);
*ptr2 = 20;
cout << *ptr1 << endl;
Warum ist die Operation abgestürzt?auto_ptr
Quellcode
Sie können sehen, dass die Kopierkonstruktion das eingehende Objekt aufruftrelease
Methode, diese Methode ist zu setzen_Right
Die Ressource, auf die verwiesen wird, wird an die neue zurückgegebenauto_ptr
Objekt und gleichzeitig_Right
(altauto_ptr
)von_Myptr
einstellennullptr
Kurz gesagt, es geht darum, das Alte zu setzenauto_ptr
Die Ressource, auf die verwiesen wird, wird dem Neuen übergebenauto_ptr
Gehalten, das alte ist eingestelltnullptr
.Daher wird der obige Code verwendet*ptr1
Einfach falsch.(auto_ptr
Lassen Sie immer den letzten Smart Pointer die Ressource verwalten)
Also,auto_ptr
Kann es in einem Container verwendet werden? Siehe den folgenden Code.
int main()
{
vector<auto_ptr<int>> vec;
vec.push_back(auto_ptr<int>(new int(10)));
vec.push_back(auto_ptr<int>(new int(20)));
vec.push_back(auto_ptr<int>(new int(30)));
cout << *vec[0] << endl; // 10
vector<auto_ptr<int>> vec2 = vec;
/* 这里由于上面做了vector容器的拷贝,
相当于容器中的每一个元素都进行了拷贝构造,
原来vec中的智能指针全部为nullptr了,
再次访问就成访问空指针了,程序崩溃
*/
cout << *vec[0] << endl; // 程序崩溃
return 0;
}
Daher ist es in C++ veraltetauto_ptr
, es sei denn, das Anwendungsszenario ist sehr einfach.Undauto_ptr
In C++11 veraltet und in C++17 vollständig entfernt
Zusammenfassen:auto_ptr
Intelligente Zeiger verfügen nicht über eine Referenzzählung, sodass sie das Problem des flachen Kopierens lösen, indem sie das Vorherige direkt kopierenauto_ptr
eingestellt sindnullptr
, lass nur das Letzteauto_ptr
Ressourcen halten
Sie müssen die Boost-Bibliothek installieren, die die Header-Dateien enthält.#include <boost/scoped_ptr.hpp>
Einsatzbereit
Schau malscoped_ptr
Quellcode:
template<class T> class scoped_ptr
{
private:
scoped_ptr(scoped_ptr const&);
scoped_ptr& operator=(scoped_ptr const&);
...
};
kann gesehen werdenscoped_ptr
Sowohl der Kopierkonstruktor als auch die Zuweisungsfunktion sind privatisiert, sodass das Objekt diese beiden Vorgänge nicht unterstützt und nicht aufgerufen werden kann, was das Auftreten flacher Kopien grundsätzlich verhindert.
Alsoscoped_ptr
Es kann nicht in Containern verwendet werden, wenn Container einander Werte kopieren oder zuweisenscoped_ptr
Objektkopiekonstruktor und Zuweisungsfunktion, Kompilierungsfehler
scoped_ptr
Undauto_ptr
Der Unterschied: Kann durch Besitz erklärt werden,auto_ptr
Das Eigentum an Ressourcen kann nach Belieben übertragen werdenscoped_ptr
Das Eigentum wird nicht übertragen (da Kopierkonstruktoren und Zuweisungsfunktionen deaktiviert sind)
scoped_ptr
Im Allgemeinen nicht verwendet
Schauen Sie sich das erst einmal anunique_ptr
Teil des Quellcodes:
template<class _Ty, class _Dx>
class unique_ptr
{
public:
/*提供了右值引用的拷贝构造函数*/
unique_ptr(unique_ptr&& _Right) { ... }
/*提供了右值引用的operator=赋值重载函数*/
unique_ptr& operator=(unique_ptr&& _Right) { ... }
/*
删除了unique_ptr的拷贝构造和赋值函数,
因此不能做unique_ptr智能指针对象的拷贝构造和赋值,
防止浅拷贝的发生
*/
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
};
Von oben gesehen,unique_ptr
ein bisschenscoped_ptr
Dasselbe geschieht, d. h. die überlasteten Kopierkonstruktions- und Zuweisungsfunktionen werden deaktiviert und Benutzern ist die Verwendung untersagtunique_ptr
Führen Sie eine explizite Kopierkonstruktion und -zuweisung durch, um das Auftreten von Smart-Pointer-Flachkopieproblemen zu verhindern.
Da es keinen Kopierkonstruktor gibt,unique_ptr<int> p1(new int()); unique_ptr<int> p2(p1);
Natürlich ist es falsch
Aberunique_ptr
Stellt Kopierkonstruktoren und Zuweisungsfunktionen mit R-Wert-Referenzparametern bereit, d. h.unique_ptr
Intelligente Zeiger können Kopierkonstruktions- und Zuweisungsvorgänge über R-Wert-Referenzen ausführen oder generierenunique_ptr
Ein Ort für temporäre Gegenstände, z.Bunique_ptr
Als Rückgabewert der Funktion lautet der Beispielcode wie folgt:
// 示例1
unique_ptr<int> p1(new int());
unique_ptr<int> p2(move(p1)); // 使用了右值引用的拷贝构造
p2 = move(p1); // 使用了右值引用的operator=赋值重载函数
// 示例2
unique_ptr<int> test_uniqueptr()
{
unique_ptr<int> ptr(new int());
return ptr;
}
int main()
{
/*
此处调用test_uniqueptr函数,在return ptr代码处,
调用右值引用的拷贝构造和赋值函数
*/
unique_ptr<int> p = test_uniqueptr(); // 调用带右值引用的拷贝构造函数
p = test_uniqueptr(); // 调用带右值引用的operator=赋值重载函数
return 0;
}
Dann benutzeunique_ptr
Der Vorteil besteht darin, dass Benutzer so etwas verwenden könnenunique_ptr<int> p2(move(p1));
Aussage, das ist deutlich zu erkennenp1
Übertragene Ressourcen anp2
,p1
Bei Verwendung werden keine weiteren Ressourcen gespeichertauto_ptr
Es wird nicht explizit seinmove
Ausgeschrieben ist die Absicht nicht offensichtlich. Wenn Sie die zugrunde liegende Ebene nicht verstehen, werden Sie sie falsch verwenden.
Zur gleichen Zeit, vonunique_ptr
Wie aus dem Namen hervorgeht, kann es am Ende nur einen Smart Pointer geben, der auf eine Ressource verweist. Daher wird empfohlen, der Verwendung von Smart Pointern ohne Referenzzählung Vorrang einzuräumen.unique_ptr
Intelligente Zeiger mit Referenzzählung umfassen hauptsächlichshared_ptr
Undweak_ptr
, mit ReferenzzählungNutzenDas heißt, mehrere Smart Pointer können dieselbe Ressource verwalten. Was sind Smart Pointer mit Referenzzählung?
Mit Referenzzählung: Passen Sie einen Referenzzähler für die Ressource jedes Objekts an.
Wenn mehrere intelligente Zeiger auf dieselbe Ressource verweisen dürfen, erhöht jeder intelligente Zeiger den Referenzzähler der Ressource um 1. Wenn ein intelligenter Zeiger zerstört wird, verringert er auch den Referenzzähler der Ressource um 1 Wenn der Referenzzähler einer Ressource von 1 auf 0 sinkt, bedeutet dies, dass die Ressource freigegeben werden kann. Der Destruktor des letzten Smart Pointers übernimmt die Freigabe der Ressource.
Nehmen Sie, was zuvor implementiert wurdeCSmartPtr
Nehmen Sie Änderungen vor und laden Sie den Code direkt hoch:
// 对资源进行引用计数的类
template<typename T>
class RefCnt
{
public:
RefCnt(T* ptr = nullptr) : mptr(ptr)
{
if (mptr != nullptr)
mcount = 1;
}
void addRef() { mcount++; } // 增加资源的引用计数
int delRef() { return --mcount; }
private:
T* mptr;
int mcount;
};
template<typename T>
class CSmartPtr
{
public:
CSmartPtr(T* ptr = nullptr) : mptr(ptr)
{
// 智能指针构造的时候给资源建立引用计数对象
mpRefCnt = new RefCnt<T>(mptr);
}
~CSmartPtr()
{
if (0 == mpRefCnt->delRef())
{
delete mptr;
mptr = nullptr;
}
}
// 实现拷贝构造
CSmartPtr(const CSmartPtr<T>& src)
:mptr(src.mptr), mpRefCnt(src.mpRefCnt)
{
if (mptr != nullptr)
mpRefCnt->addRef();
}
CSmartPtr<T>& operator=(const CSmartPtr<T>& src)
{
// 防止自赋值
if (this == &src)
return *this;
// 本身指向的资源减1
// 如果减1为0释放资源;如果减1不为0直接走
if (0 == mpRefCnt->delRef()) { delete mptr; }
mptr = src.mptr;
mpRefCnt = src.mpRefCnt;
mpRefCnt->addRef();
return *this;
}
T& operator*() { return *mptr; }
T* operator->() { return mptr; }
private:
T* mptr; // 指向资源的指针
RefCnt<T>* mpRefCnt; // 指向该资源引用计数对象的指针
};
// 那么现在就不会报错了,不会对同一个资源释放多次
CSmartPtr<int> ptr1(new int());
CSmartPtr<int> ptr2(ptr1);
CSmartPtr<int> ptr3;
ptr3 = ptr2;
*ptr1 = 20;
cout << *ptr2 << " " << *ptr3 << endl; // 20 20
Dadurch können mehrere Smart Pointer dieselbe Ressource verwalten.
Allerdings sind die intelligenten Zeiger, die wir jetzt implementieren, nicht threadsicher und können nicht in Multithread-Szenarien verwendet werden.Umgesetzt von Curryshared_ptr
Undweak_ptr
Es ist threadsicher!
shared_ptr
:mächtigIntelligente Zeiger (können die Referenzanzahl von Ressourcen ändern)weak_ptr
:schwachIntelligente Zeiger (verändern den Referenzzähler der Ressource nicht)Was wir im vorherigen Abschnitt implementiert habenCSmartPtr
Auch ein starker intelligenter Zeiger (kann den Referenzzähler der Ressource ändern)
Es kann so verstanden werden: Schwacher intelligenter Zeiger beobachten Starke intelligente Zeiger Starke intelligente Zeigerbeobachten Ressourcen (Speicher)
Also,Starkes Problem mit Smart-Pointer-Querverweisen (Zirkelverweisen). was ist es dann?Kommen Sie vorbei und schauen Sie es sich an
class B; // 前置声明类B
class A
{
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
shared_ptr<B> _ptrb; // 指向B对象的智能指针
};
class B
{
public:
B() { cout << "B()" << endl; }
~B() { cout << "~B()" << endl; }
shared_ptr<A> _ptra; // 指向A对象的智能指针
};
int main()
{
shared_ptr<A> pa(new A()); // pa指向A对象,A的引用计数为1
shared_ptr<B> pb(new B()); // pb指向B对象,B的引用计数为1
pa->_ptrb = pb; // A对象的成员变量_ptrb也指向B对象,B的引用计数为2
pb->_ptra = pa; // B对象的成员变量_ptra也指向A对象,A的引用计数为2
cout << pa.use_count() << endl;
cout << pb.use_count() << endl;
return 0;
}
Operationsergebnis:
A()
B()
2
2
Wie Sie sehen können, werden A und B nicht zerstört, was bedeutet, dass es zu Querverweisen kommtnew
Die austretenden Ressourcen können nicht freigegeben werden, was zu einem Ressourcenverlust führt!
analysieren:
ausmain
Funktionsumfang,pa
Undpb
Zwei lokale Objekte werden zerstört und die Referenzanzahl von Objekt A und Objekt B wird von 2 auf 1 reduziert. Die Bedingungen für die Freigabe von A und B können nicht erfüllt werden (die Bedingung für die Freigabe ist, dass die Referenzanzahl von A und B reduziert wird). auf 0), wodurch zwei verursacht werdennew
Die ausgegebenen A- und B-Objekte können nicht freigegeben werden, was zu Speicherverlusten führtStarkes Problem mit Smart-Pointer-Querverweisen (Zirkelverweisen).
Lösung: Verwenden Sie beim Definieren von Objekten starke intelligente Zeiger und beim Referenzieren von Objekten schwache intelligente Zeiger.
class B; // 前置声明类B
class A
{
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
weak_ptr<B> _ptrb; // 指向B对象的弱智能指针(引用对象时,用弱智能指针)
};
class B
{
public:
B() { cout << "B()" << endl; }
~B() { cout << "~B()" << endl; }
weak_ptr<A> _ptra; // 指向A对象的弱智能指针(引用对象时,用弱智能指针)
};
int main()
{
// 定义对象时,用强智能指针
shared_ptr<A> pa(new A()); // pa指向A对象,A的引用计数为1
shared_ptr<B> pb(new B()); // pb指向B对象,B的引用计数为1
// A对象的成员变量_ptrb也指向B对象,B的引用计数为1,因为是弱智能指针,引用计数没有改变
pa->_ptrb = pb;
// B对象的成员变量_ptra也指向A对象,A的引用计数为1,因为是弱智能指针,引用计数没有改变
pb->_ptra = pa;
cout << pa.use_count() << endl; // 1
cout << pb.use_count() << endl; // 1
return 0;
}
Operationsergebnis:
A()
B()
1
1
~B()
~A()
kann gesehen werden, rausmain
Funktionsumfang,pa
Undpb
Die beiden lokalen Objekte werden zerstört und die Referenzanzahl von Objekt A und Objekt B wird von 1 auf 0 reduziert, wodurch die Bedingungen für die Freigabe von A und B erreicht werden. Daher gilt:new
Das A-Objekt und das B-Objekt, die herauskamen, wurden zerstört, wodurch das Problem gelöst wurde.Starkes Problem mit Smart-Pointer-Querverweisen (Zirkelverweisen).
kann gesehen werden,weak_ptr
Schwache intelligente Zeiger ändern den Referenzzähler der Ressource nicht, was bedeutet, dass schwache intelligente Zeiger nur beobachten, ob das Objekt aktiv ist (ob der Referenzzähler 0 ist), und die Ressource nicht verwenden können.
Fügen Sie dann, wenn zu diesem Zeitpunkt, Klasse A hinzuvoid testA() { cout << "非常好用的方法!!" << endl; }
Eine solche Methode ergänzt Bvoid func() { _ptra->testA(); }
Ist es in Ordnung, diese Methode aufzurufen?
*
Und->
Überladene Funktionen von Operatoren können keine Funktionen verwenden, die Rohzeigern ähnelnLösung:
class B; // 前置声明类B
class A
{
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
void testA() { cout << "非常好用的方法!!" << endl; }
weak_ptr<B> _ptrb; // 指向B对象的弱智能指针(引用对象时,用弱智能指针)
};
class B
{
public:
B() { cout << "B()" << endl; }
~B() { cout << "~B()" << endl; }
void func()
{
shared_ptr<A> sp = _ptra.lock(); // 提升方法,出函数作用域就自动析构了
if (sp != nullptr)
sp->testA();
}
weak_ptr<A> _ptra; // 指向A对象的弱智能指针(引用对象时,用弱智能指针)
};
int main()
{
shared_ptr<A> pa(new A());
shared_ptr<B> pb(new B());
pa->_ptrb = pb;
pb->_ptra = pa;
cout << pa.use_count() << endl; // 1
cout << pb.use_count() << endl; // 1
pb->func();
return 0;
}
Obwohl
weak_ptr
besitzt das Objekt nicht, kann es aber passierenlock()
Die Methode versucht, einen Zeiger auf das Objekt zu erhaltenshared_ptr
, wenn das Objekt noch lebt (d. h. es andere gibt).shared_ptr
Zeige auf es),lock()
gibt einen Zeiger auf das Objekt zurückshared_ptr
; Andernfalls wird ein leerer Wert zurückgegebenshared_ptr
verwenden
lock()
Ein typisches Szenario für Methoden ist, wenn temporärer Zugriff erforderlich istweak_ptr
das Objekt, auf das gezeigt wird, und möchten gleichzeitig die Lebensdauer des Objekts nicht erhöhen
Operationsergebnis:
A()
B()
1
1
非常好用的方法!!
~B()
~A()
An dieser Stelle erkennt man, dass es richtig aufgerufen wurde!
Schauen wir uns eins anThread-Sicherheitsprobleme beim Zugriff auf gemeinsam genutzte Objekte von mehreren Threads aus: Thread A und Thread B greifen auf ein gemeinsam genutztes Objekt zu, Thread B muss die Member-Methode des gemeinsam genutzten Objekts aufrufen. Zu diesem Zeitpunkt hat Thread A möglicherweise die Zerstörung des Objekts abgeschlossen, Thread B jedoch nicht Wenn Sie versuchen, auf das Objekt zuzugreifen, tritt ein unerwarteter Fehler auf.
Schauen Sie sich zunächst den folgenden Code an:
class A
{
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
void testA() { cout << "非常好用的方法!!" << endl; }
};
// 子线程
void handler01(A* q)
{
// 睡眠两秒,此时main主线程已经把A对象给delete析构掉了
std::this_thread::sleep_for(std::chrono::seconds(2));
q->testA();
}
// main线程
int main()
{
A* p = new A();
thread t1(handler01, p);
delete p;
//阻塞当前线程,直到调用join()的线程结束
t1.join();
return 0;
}
in der Ausführungq->testA();
Wenn diese Aussage gemacht wird, wird diemain
Das gemeinsam genutzte Objekt wurde vom Thread zerstört, was offensichtlich unvernünftig ist.
Wenn du bestehen willstq
Wenn der Zeiger auf das A-Objekt zugreifen möchte, muss er feststellen, ob das A-Objekt aktiv ist. Wenn das A-Objekt aktiv ist, rufen Sie auftestA
Es gibt kein Problem mit der Methode; wenn das A-Objekt zerstört wurde, rufen Sie es auftestA
hat ein Problem!Das heißtq
Beim Zugriff auf Objekt A müssen Sie feststellen, ob Objekt A aktiv ist. Wie lässt sich dieses Problem lösen? Sie müssen starke und schwache intelligente Zeiger verwenden.
Schauen wir uns diesen Code an:
// 子线程
void handler01(weak_ptr<A> wp)
{
// 睡眠两秒
std::this_thread::sleep_for(std::chrono::seconds(2));
shared_ptr<A> sp = wp.lock();
if (sp != nullptr)
sp->testA();
else
cout << "A对象已经析构,不能再访问!" << endl;
}
// main线程
int main()
{
shared_ptr<A> p(new A());
thread t1(handler01, weak_ptr<A>(p));
t1.join();
return 0;
}
Operationsergebnis:
A()
非常好用的方法!!
~A()
Man sieht, dass es läuftsp->testA();
,Weilmain
Der Thread hat aufgerufent1.join()
Die Methode wartet auf das Ende des untergeordneten Threadswp
passierenlock
Erfolgreich befördertsp
Ändern Sie den obigen Code:
// 子线程
void handler01(weak_ptr<A> wp)
{
// 睡眠两秒
std::this_thread::sleep_for(std::chrono::seconds(2));
shared_ptr<A> sp = wp.lock();
if (sp != nullptr)
sp->testA();
else
cout << "A对象已经析构,不能再访问!" << endl;
}
// main线程
int main()
{
{
shared_ptr<A> p(new A());
thread t1(handler01, weak_ptr<A>(p));
t1.detach();
}
std::this_thread::sleep_for(std::chrono::seconds(3));
return 0;
}
Operationsergebnis:
A()
~A()
A对象已经析构,不能再访问!
Wie Sie sehen, legen wir einen Umfang fest und legen auch festt1
Um Threads zu trennen, verwenden Sie intelligente Zeigerp
Wenn A außerhalb des Gültigkeitsbereichs zerstört wird, wird es zu diesem Zeitpunkt gedrucktA对象已经析构,不能再访问!
, das istwp
passierenlock
Das Upgrade auf konnte nicht erfolgreich durchgeführt werdensp
Das Obige ist das Thread-Sicherheitsproblem, wenn Multithreads auf gemeinsam genutzte Objekte zugreifenshared_ptr
Undweak_ptr
Eine typische Anwendung.
Referenzartikel:Tiefes Verständnis der C++-Smartpointer