經常有人建議在現代C++中不要使用原始指針,除少數情況外。在C++庫API中使用智能指針的常見做法是什麼?C++ API中的智能指針?
以下案例拿出來我的腦海:
- 它返回一個新的對象的功能。
- 一個函數,它返回一個新的對象,但它也創建了另一個對這個對象的引用。
- 一個只使用它接收的對象作爲參數的函數。
- 接管對象所有權的函數。
- 一個將存儲對象的引用作爲參數的函數,但可能還有其他對象(來自調用方)的引用。
經常有人建議在現代C++中不要使用原始指針,除少數情況外。在C++庫API中使用智能指針的常見做法是什麼?C++ API中的智能指針?
以下案例拿出來我的腦海:
獨特的指針可以在一般情況下做的工作。
std::unique_ptr<Foo> func();
所以,你可以直接將其分配到的呼叫者網站auto
變量,而不用擔心內存管理。
auto u = func();
如果你需要共享所有權,你可以轉換在呼叫者現場智能指針:
std::shared_ptr<Foo> s{func()};
然而,如果該函數的返回類型不是多態的,和該類型快速移動,你可以通過值喜歡回報:
Foo func();
分享d指針。
std::shared_ptr<Foo> func();
只需使用到的對象的引用或const引用,與原始指針或智能指針「引用」的呼叫者的網站。
void func(Foo& obj);
void func(const Foo& obj);
萬一參數都是可選的,你可以使用原始指針,這樣就可以很容易地通過一個nullptr
給他們。
void func(Foo *obj);
void func(const Foo *obj);
獨特的指針。
void func(std::unique_ptr<Foo> obj);
const對共享指針的引用。
void func(const std::shared_ptr<Foo>& obj);
的常量引用(共享指針)是簡單地防止調整基準計數時調用該函數時,當它返回一個優化。
1.按價值回報。 3.取決於功能是否需要本地副本。 – juanchopanza
我同意 - 雖然#3也可以是純原始指針,如果'nullptr'是一個有效的參數。現代C++中的原始指針作爲函數參數只是意味着「可以爲null,但我不會承認您給我的任何所有權」。 –
@juanchopanza取決於,例如移動該對象的代價是多少,以及返回類型是否是基類指針(考慮工廠)。 –
不幸的是,庫API的設計遠遠超出了語言本身的規則:突然你要關心的實現細節,如ABI。與C相反,C++實現可以很容易地交互在一起,C++實現具有非常不同的ABI(Microsoft ABI for VC++完全不兼容gcc和Clang使用的Itanium ABI),並且C++標準庫實現也不兼容所以如果std::
類出現在界面中,那麼使用libstdC++(捆綁了gcc)編譯的庫不能被使用另一個主要版本的libstdC++或另一個實現(如libC++(與Clang捆綁))的程序使用。
因此,這實際上取決於您是否打算將庫作爲二進制文件交付,或者假定用戶將能夠使用自己的編譯器和標準庫實現選擇來編譯庫。只有在後一種情況下,你應該公開一個C++接口,對於二進制發行版來說,堅持C是更好的(並且與其他語言的集成也更容易)。
有了這樣的方式,讓我們假設你決定使用C++ API:
1),它返回一個新的對象的功能。
如果該對象可以通過值返回,那麼;如果它是多態的,則使用std::unique_ptr<Object>
。
2)函數返回一個新的對象,但它也創建了另一個對這個對象的引用。
罕見案例。我想你的意思是它保留了一個參考,不知何故。在這種情況下,您擁有共享所有權,因此明顯的選擇是std::shared_ptr<Object>
。
3)僅使用它接收的對象作爲參數的函數。
比第一次看起來複雜得多,甚至假設沒有保留對象的引用。
const
與否)4)接管對象所有權的函數。
簡單所有權:std::unique_ptr<Object>
。
5)一個函數,它將存儲對象的引用作爲參數接收,但可能還有其他對象(來自調用者方)的引用。
共享所有權:std::shared_ptr<Object>
請注意,庫C二進制API可以封裝在由客戶端編譯的僅頭文件C++ API中。 – Yakk
@Yakk:和Clang一樣,你有一個核心的C++實現,它暴露一個C API(用於二進制穩定性),並決定將它封裝在僅用於頭文件的C++ API中(以便於使用))。 –
「5.一種函數[存儲]參考[...,]不關心其他潛在的引用。」 - 這是模糊的。它並不關心,因爲它知道物體的壽命將超過它的使用壽命?如果是這樣,它可以採用引用的地址或接受原始指針。如果它不知道,那麼它最終需要一個弱指針。 –
我的意思是說要麼是對象是不可變的(即共享以減少內存使用),要麼是通過其他別名來突變對象,這根本就沒有問題。 –
我編輯了這個問題,我希望現在更清楚。 –