[英]C++ idiomatic way for nullable reference
我正在編寫一個函數,它應該接受const std::string &
,但也是一個特殊的nullptr
值。 目前,我正在使用const std::string *
。 但是,我覺得應該有更多的C ++ - ish方式來執行此任務。
我最強的對應點是傳遞值(字符串不會很長,但64kB不是我想復制的東西)。 這也意味着我不希望像optional<T>
這樣的對象具有類型為T
的值字段。 另外,我不想使用任何外部庫。 我的項目沒有使用Boost或GSL,只是簡單的C ++(確切地說是C ++ 17)。
是否存在標准庫類(奇跡出現在namespace std
)或廣泛接受的習慣用語?
如果std::optional
支持引用,那么它就是花哨的“現代”方式。
但:
歷史悠久,久經考驗且清晰易讀的解決方案是采用指針。 這種方法完全可以滿足您的所有需求。
只要這樣做,然后繼續把你寶貴的時間花在更重要的事情上!
這個問題的一個有趣的方面是我更常見的反向透視:C ++方式指定一個不允許為空的指針是什么? 答案歸結為相同的原則。
指針引用的主要區別是:
如果你使指針不變,第一個區別就會消失。 擁有“可空引用”的C ++方法是擁有一個常量指針。 請注意,我所說的指針是常量,如T * const
,它與指向對象的常量無關,如T const *
或const T *
。
你可能已經接受過訓練,認為所有的指針都是邪惡的,但這是一種過度概括。 原始指針是引用您不負責的內存的可選對象的好方法。 如果您負責釋放內存,請使用智能指針,但如果其他人正在為您保留內存,請使用引用或指針。 如果需要對象,則使用引用(不能為null); 如果它是可選的指針(可以為null)。 哦,這假設您不需要更改指向的對象,在這種情況下,引用將不再是一個選項。
話雖如此,在特定情況下可能有其他選擇。 如果null和not-null之間沒有共享代碼,那么重載函數可能會更好,比如void foo(const std::string &)
和void foo()
。 這必須與各種權衡取得平衡,包括API一致性。 選擇最適合您情況的方法。
另一種方法是提供一個空字符串,您的函數可以通過對象標識檢查來檢測:
#include <string>
namespace MyLibrary
{
static const std::string NULL_STRING;
void foo(const std::string& str)
{
if (&str == &NULL_STRING)
// ...
else
// ...
}
}
int main()
{
MyLibrary::foo("Hello, world!");
MyLibrary::foo("");
MyLibrary::foo(MyLibrary::NULL_STRING);
}
不過,人們可能會認為這有點浪費空間,我並不認為這是特別慣用的。 但是,我有時在私有庫代碼中采用了類似的方法(特別是與默認參數相結合)。
正如你特別要求一些STD庫奇跡一樣:STD庫實際上有一個reference_wrapper
,它可以與optional
結合使用,以達到你的要求:
template <class T>
using optional_ref = std::optional<std::reference_wrapper<T>>;
它實際上非常直接,但也有點笨拙的訪問:
void foo(optional_ref<std::string> str)
{
if (str)
printf("%s", str->get().c_str());
}
從調用站點它工作得很好:
std::string str;
foo(str); // passes a reference
foo({}); // passes nothing
話雖如此,我也不認為使用;)(見接受的答案)。
寫兩個功能:
void f(const string *s)
{
if (s)
{
// Use s
}
else
{
// Don't use s
}
}
void f(const string &s)
{
f(&s);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.