C++基礎::shared_ptr 程式設計細節(一)
智慧指標是c++ 中管理資源的一種方式,用智慧指標管理資源,不必擔心資源洩露,將 c++ 程式設計師從指標和記憶體管理中解脫出來。
shared_ptr 的兩面性
shared_ptr 型智慧指標物件的本質是類例項;
所以允許
.+成員函式
的呼叫方式(這裡的成員函式是 shared_ptr 作為類例項所具有的成員函式),比如一個shared_ptr
最為類例項的成員函式:- .use_count()
- .get()
- .reset()
- .unique()
- …
含義上作為智慧指標的一面
所以允許
->成員函式
的呼叫方式(這裡的成員函式為智慧指標所維護的真實物件所具有的成員函式)。
shared_ptr 的副作用
shared_ptr:一種智慧指標,本意封裝原生指標(new 出來的堆物件),實現指標的型別安全,然而,見名知意,它是共享型指標,即允許多個shared_ptr“指向”同一個物件,當我們在某些情況下不需要這一看似美好的性質時,該如何處理呢。
class Item
{
private:
std::string _name;
float _price;
public:
Item(const std::string& name, float price):_name(name),
_price(price){}
float getPrice() const { return _price;}
void setPrice(float price) { _price = price;}
Item* clone() const { return new Item(*this);}
};
// 單純為了演示的需要,並無實際的意義
class A
{
public:
A(const std::shared_ptr<Item>& obj):_obj(obj){}
const std::shared_ptr<Item>& get() const
{ return _obj;}
private:
std::shared_ptr<Item> _obj;
};
int main(int, char**)
{
std::shared_ptr<Item> item1(new Item("C++", 20.));
A a(item1);
// 此時檢視item1的引用次數:
std::cout << item1.use_count() << std::endl;
// 2
// 如果使用物件a對內部的_obj進行修改,會同步到item1中
a.get()->setPrice(30.);
std::cout << item1->getPrice() << std::endl;
// 這時我們建立另外一個A物件
A b(a);
// 這時如果不對A的拷貝構造進行過載的話,b也會持有一份對item1物件的引用
std::cout << item1.use_count() << std::endl;
// 3
return 0;
}
這就是shared_ptr
共享型智慧指標的便捷和侷限。那麼,我們該如何使用拷貝構造時,建立自己獨特的副本呢?
我們需要顯式地給出A的拷貝構造,避免編譯器對拷貝構造的預設實現:
class A
{
...
public:
A(const A& other)
{
_obj = std::shared_ptr<Item>(other.get()->clone());
}
}
所以結論是,在一個需被 shared_ptr 封裝的類內部給出非常關鍵 clone() 函式的實現非常關鍵 ;
Obj* clone() const { return new Obj(*this); }
以 shared_ptr 類型別為容器型別的容器之間的賦值
是繼續持有物件的引用,還是一份全新的拷貝;
std::shared_ptr<Item> item1(new Item("C++", 20.5));
std::shared_ptr<Item> item2(new Item("Python", 25.5));
std::vector<std::shared_ptr<Item>> v1 = {item1, item2};
std::vector<std::shared_ptr<Item>> v2 = v1;
// 繼續持有引用
std::cout << item1.use_count() << std::endl;
// 3
item1->setPrice(30.);
std::cout << v2[0]->getPrice() << std::endl;
std::vector<std::shared_ptr<Item>> v3;
for (size_t i = 0; i < v1.size(); ++i)
v3.push_back(std::shared_ptr<Item>(v1[i]->clone()));
// 一份全新的拷貝
item2->setPrice(35.5);
std::cout << v3[1]->getPrice() << std::endl;
// 25.5
相關文章
- iOS基礎細節iOS
- C++程式設計基礎(2)變數C++程式設計變數
- C++程式設計基礎實驗1C++程式設計
- JNI程式設計基礎(一)程式設計
- JavaWeb—Servlet基礎(細節版,相當細節)JavaWebServlet
- 詳細講解DirectDraw程式設計基礎(轉)程式設計
- C++基礎回顧4——智慧指標shared_ptrC++指標
- C++在C的基礎上改進了哪些細節C++
- JS基礎細節知識JS
- C++ 泛型程式設計基礎:模板通識C++泛型程式設計
- 大規模C++程式設計 -- 基礎知識C++程式設計
- 程式設計基礎程式設計
- 那些害死程式設計師的細節程式設計師
- 併發程式設計——基礎概念(一)程式設計
- C++ 遞迴與物件導向程式設計基礎C++遞迴物件程式設計
- Python——基礎知識細節Python
- Socket程式設計基礎程式設計
- Go程式設計基礎Go程式設計
- Java程式設計基礎Java程式設計
- Shell程式設計-基礎程式設計
- C程式設計基礎C程式程式設計
- shell程式設計基礎程式設計
- Go 併發程式設計 - Goroutine 基礎 (一)Go程式設計
- 網路程式設計基礎-socket基礎程式設計
- 漫談程式設計師系列:那些害死程式設計師的細節程式設計師
- Javascript基礎與物件導向基礎~第一講啥叫程式設計,啥叫程式設計師JavaScript物件程式設計師
- 程式設計師面試 IT 公司,這些細節一定要注意!程式設計師面試
- 程式設計師的快樂:那些小細節程式設計師
- Java 基礎02Java程式設計基礎Java程式設計
- Java併發程式設計——基礎知識(一)Java程式設計
- PLC(一)可程式設計控制器基礎程式設計
- 程式設計之基礎:資料型別(一)程式設計資料型別
- linux下bluetooth程式設計(一)基礎概念Linux程式設計
- 程式設計基礎知識程式設計
- shell程式設計基礎二程式設計
- 【程式設計基礎】輸出程式設計
- 【socket程式設計基礎模板】程式設計
- 網路程式設計基礎程式設計