智能指針是c++++中自動(dòng)管理內(nèi)存的工具,主要包括unique_ptr、shared_ptr和weak_ptr。1. unique_ptr用于獨(dú)占所有權(quán),不可復(fù)制,轉(zhuǎn)移需用std::move,銷毀時(shí)自動(dòng)刪除對(duì)象;2. shared_ptr允許多個(gè)指針共享同一對(duì)象,通過(guò)引用計(jì)數(shù)管理生命周期,但需注意循環(huán)引用問(wèn)題;3. weak_ptr作為弱引用不增加引用計(jì)數(shù),用于解決循環(huán)引用及實(shí)現(xiàn)緩存等場(chǎng)景。合理選擇智能指針可避免內(nèi)存泄漏并提升效率。
智能指針,說(shuō)白了,就是幫你自動(dòng)管理內(nèi)存的指針?,F(xiàn)代 c++ 里,它們已經(jīng)是標(biāo)配了,unique_ptr、shared_ptr 和 weak_ptr,各有各的用處和側(cè)重點(diǎn),用錯(cuò)了地方,輕則效率打折,重則內(nèi)存泄漏。
unique_ptr、shared_ptr、weak_ptr 就像是內(nèi)存管理戰(zhàn)場(chǎng)上的三員大將,各有千秋,用對(duì)了地方才能發(fā)揮最大威力。
解決方案
首先,unique_ptr,顧名思義,它所指向的對(duì)象只能被一個(gè) unique_ptr 擁有。這意味著,所有權(quán)是獨(dú)占的,不能簡(jiǎn)單地復(fù)制。當(dāng) unique_ptr 銷毀時(shí),它所指向的對(duì)象也會(huì)被自動(dòng)刪除。這避免了忘記 delete 造成的內(nèi)存泄漏。
立即學(xué)習(xí)“C++免費(fèi)學(xué)習(xí)筆記(深入)”;
#include <iostream> #include <memory> class MyClass { public: MyClass(int value) : value_(value) { std::cout << "MyClass constructed with value: " << value_ << std::endl; } ~MyClass() { std::cout << "MyClass destructed with value: " << value_ << std::endl; } int getValue() const { return value_; } private: int value_; }; int main() { // 創(chuàng)建一個(gè) unique_ptr,指向一個(gè) MyClass 對(duì)象 std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>(10); std::cout << "Value: " << ptr1->getValue() << std::endl; // 嘗試復(fù)制 unique_ptr 會(huì)導(dǎo)致編譯錯(cuò)誤 // std::unique_ptr<MyClass> ptr2 = ptr1; // 錯(cuò)誤:unique_ptr 不可復(fù)制 // 可以使用 std::move 轉(zhuǎn)移所有權(quán) std::unique_ptr<MyClass> ptr2 = std::move(ptr1); std::cout << "Value: " << ptr2->getValue() << std::endl; // 現(xiàn)在 ptr1 不再擁有對(duì)象,訪問(wèn)它會(huì)導(dǎo)致未定義行為 // std::cout << "Value: " << ptr1->getValue() << std::endl; // 避免這樣做 // ptr2 在 main 函數(shù)結(jié)束時(shí)會(huì)被銷毀,MyClass 對(duì)象也會(huì)被銷毀 return 0; }
shared_ptr 則允許多個(gè)指針指向同一個(gè)對(duì)象,它使用引用計(jì)數(shù)來(lái)跟蹤有多少個(gè) shared_ptr 指向該對(duì)象。只有當(dāng)引用計(jì)數(shù)降為零時(shí),對(duì)象才會(huì)被刪除。這使得在多個(gè)對(duì)象之間共享所有權(quán)變得非常方便。但是,循環(huán)引用會(huì)導(dǎo)致內(nèi)存泄漏,需要小心。
#include <iostream> #include <memory> class MyClass { public: MyClass(int value) : value_(value) { std::cout << "MyClass constructed with value: " << value_ << std::endl; } ~MyClass() { std::cout << "MyClass destructed with value: " << value_ << std::endl; } int getValue() const { return value_; } private: int value_; }; int main() { // 創(chuàng)建一個(gè) shared_ptr,指向一個(gè) MyClass 對(duì)象 std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>(20); std::cout << "Value: " << ptr1->getValue() << std::endl; std::cout << "Reference count: " << ptr1.use_count() << std::endl; // 復(fù)制 shared_ptr,引用計(jì)數(shù)增加 std::shared_ptr<MyClass> ptr2 = ptr1; std::cout << "Value: " << ptr2->getValue() << std::endl; std::cout << "Reference count: " << ptr1.use_count() << std::endl; std::cout << "Reference count: " << ptr2.use_count() << std::endl; // ptr1 和 ptr2 都指向同一個(gè)對(duì)象,該對(duì)象在 main 函數(shù)結(jié)束時(shí)會(huì)被銷毀一次 return 0; }
最后,weak_ptr 是一種“弱引用”,它指向由 shared_ptr 管理的對(duì)象,但不增加引用計(jì)數(shù)。weak_ptr 可以用來(lái)觀察對(duì)象是否仍然存在,而不會(huì)阻止對(duì)象被刪除。這對(duì)于解決循環(huán)引用問(wèn)題非常有用。
#include <iostream> #include <memory> class MyClass { public: MyClass(int value) : value_(value) { std::cout << "MyClass constructed with value: " << value_ << std::endl; } ~MyClass() { std::cout << "MyClass destructed with value: " << value_ << std::endl; } int getValue() const { return value_; } private: int value_; }; int main() { // 創(chuàng)建一個(gè) shared_ptr,指向一個(gè) MyClass 對(duì)象 std::shared_ptr<MyClass> sharedPtr = std::make_shared<MyClass>(30); std::cout << "Shared pointer value: " << sharedPtr->getValue() << std::endl; std::cout << "Shared pointer reference count: " << sharedPtr.use_count() << std::endl; // 創(chuàng)建一個(gè) weak_ptr,指向同一個(gè) MyClass 對(duì)象 std::weak_ptr<MyClass> weakPtr = sharedPtr; std::cout << "Weak pointer expired: " << weakPtr.expired() << std::endl; // 可以使用 weak_ptr 的 lock() 方法獲取一個(gè) shared_ptr std::shared_ptr<MyClass> lockedPtr = weakPtr.lock(); if (lockedPtr) { std::cout << "Locked pointer value: " << lockedPtr->getValue() << std::endl; std::cout << "Shared pointer reference count: " << sharedPtr.use_count() << std::endl; } else { std::cout << "Weak pointer is expired." << std::endl; } // 釋放 shared_ptr sharedPtr.reset(); std::cout << "Shared pointer reference count: " << sharedPtr.use_count() << std::endl; std::cout << "Weak pointer expired: " << weakPtr.expired() << std::endl; // 再次嘗試使用 weak_ptr 的 lock() 方法 lockedPtr = weakPtr.lock(); if (lockedPtr) { std::cout << "Locked pointer value: " << lockedPtr->getValue() << std::endl; } else { std::cout << "Weak pointer is expired." << std::endl; } return 0; }
何時(shí)使用 unique_ptr?
當(dāng)你希望對(duì)象的所有權(quán)是唯一的,并且在 unique_ptr 銷毀時(shí)自動(dòng)刪除對(duì)象時(shí),使用 unique_ptr。例如,在工廠函數(shù)中返回新創(chuàng)建的對(duì)象,或者在類中擁有一個(gè)獨(dú)占的資源。
shared_ptr 如何避免循環(huán)引用導(dǎo)致的內(nèi)存泄漏?
循環(huán)引用是指兩個(gè)或多個(gè)對(duì)象互相持有 shared_ptr,導(dǎo)致引用計(jì)數(shù)永遠(yuǎn)不為零,對(duì)象永遠(yuǎn)無(wú)法被刪除。解決循環(huán)引用的方法是使用 weak_ptr。一個(gè)對(duì)象持有另一個(gè)對(duì)象的 weak_ptr,而不是 shared_ptr,這樣就不會(huì)增加引用計(jì)數(shù)。當(dāng)需要訪問(wèn)對(duì)象時(shí),可以使用 weak_ptr::lock() 方法獲取一個(gè) shared_ptr,如果對(duì)象已經(jīng)被刪除,lock() 方法會(huì)返回 nullptr。
weak_ptr 的使用場(chǎng)景有哪些?
除了解決循環(huán)引用問(wèn)題,weak_ptr 還可以用于緩存。例如,一個(gè)緩存對(duì)象可以使用 weak_ptr 來(lái)持有緩存項(xiàng),當(dāng)緩存項(xiàng)不再被其他對(duì)象使用時(shí),緩存對(duì)象會(huì)自動(dòng)釋放緩存項(xiàng)。還可以用于觀察者模式,觀察者可以使用 weak_ptr 來(lái)持有被觀察者的引用,當(dāng)被觀察者被刪除時(shí),觀察者可以自動(dòng)取消訂閱。