[英]How to return a const reference which is not available
假設我有以下功能:
const std::string& Cat::getKittenName() const
{
Kitten* kitty = getKitty();
return kitty->getName();
}
Kitten::getName
返回const std::string&
我如何最好地處理kitty
是nullptr
? 我可以返回std::string("")
但隨后我返回了對臨時且實際上保證未定義行為的引用。 我可以更改getKittenName
函數以返回一個std::string
來解決這個問題,但隨后我為所有kitty
可用的情況引入了一個冗余副本。 現在我覺得最好的選擇是:
const std::string& Cat::getKittenName() const
{
Kitten* kitty = getKitty();
if (kitty)
{
return kitty->getName();
}
static std::string empty("");
return empty;
}
唯一的問題可能是“魔術靜力學”不可用。 這個解決方案有什么問題,或者有更好的方法嗎?
你有幾個選擇,真的。
最簡單的一個是返回std::string
,但是你提到你出於性能原因不希望這樣做。 我會說你應首先進行分析,以確保它會出現明顯的性能問題,因為所有其他解決方案都會使代碼更復雜,因此至少有一點難以維護。 但是,讓我們說它看起來確實很重要。
如果您擔心未實現線程安全的函數范圍靜態,則可以將后備值創建為Cat
的靜態成員:
class Cat { static const std::string missingKittenName; public: const std::string& Cat::getKittenName() const { Kitten* kitty = getKitty(); if (kitty) return kitty->getName(); else return missingKittenName; } };
由於Kitten::getName()
顯然返回一個引用(否則你不會擔心副本),你也可以返回一個指針:
const std::string* Cat::getKittenName() const { Kitten* kitty = getKitty(); if (kitty) return &kitty->getName(); else return nullptr; }
您可以返回對字符串的可選引用:
boost::optional<const std::string&> Cat::getKittenName() const { Kitten* kitty = getKitty(); if (kitty) return kitty->getName(); else return boost::none; }
從C ++ 17開始, optional
是std::optional
的標准庫的一部分,因此不再需要依賴Boost。
如果缺少名稱這一事實是異常情況(錯誤),您可以拋出異常:
const std::string& Cat::getKittenName() const { Kitten* kitty = getKitty(); if (kitty) return kitty->getName(); else throw std::invalid_argument("Missing kitten"); }
返回對const static std :: string的引用。
原因:
如果你在pre-c ++ 11編譯器上有多線程,那么你需要編寫一個線程安全的單例來制作默認字符串,或者在文件范圍內定義它。
C ++ 11:
const std::string& Cat::getKittenName() const
{
static const std::string noname { /* empty string */ };
Kitten* kitty = getKitty();
if (kitty)
{
return kitty->getName();
}
return noname;
}
C ++ 03:
namespace {
const std::string noname;
}
const std::string& Cat::getKittenName() const
{
Kitten* kitty = getKitty();
if (kitty)
{
return kitty->getName();
}
return noname;
}
返回表示成功/失敗的布爾值,並通過指針傳遞輸出。
這是一個例子:
bool Cat::getKittenName(std::string *name) const {
Kitten* kitty = getKitty();
if (kitty) {
*name = kitty->getName();
return true;
}
return false;
}
您將使用如下:
std::string name;
if(mycat.getKittenName(&name)) {
// name is populated and is valid
}
這要求由指針傳入的類具有有效的復制構造函數和復制賦值運算符。
我喜歡這樣做有幾個原因:
例如上面列出的示例:
const std::string* Cat::getKittenName() const
{
Kitten* kitty = getKitty();
if (kitty)
return &kitty->getName();
else
return nullptr;
}
將被稱為這樣:
const std::string *name = mykitty.getKittenName();
好的..現在怎么樣? 我無法使用此指針更改name的值,但是我可以更改指針指向的內容嗎? 我應該把它包裝成一個
std::unique_ptr<const std::string>
?? 一般來說,返回指針非常C-esque,並且是一個很大的內存泄漏和錯誤來源,除了令人困惑。
這個例子:
const std::string& Cat::getKittenName() const
{
Kitten* kitty = getKitty();
if (kitty)
return kitty->getName();
else
throw std::invalid_argument("Missing kitten");
}
我不是粉絲,因為它鼓勵為非特殊行為拋出異常。 例如,如果你在一組小貓上寫了一個名為'find()'的方法。 沒有找到特定名字的小貓並不是“例外”。 STL使用各種機制,如std :: end和std :: pair,以避免為非異常行為拋出異常。
這產生的另一個問題是,與Java不同,它並不完全清楚代碼中拋出異常的地方,如果你沒有意識到拋出的東西,傳遞調用無法正常清理。 這在拋出異常的庫中尤其邪惡。
我更喜歡以下風格:
retval method(const input&, pointer *output) { }
因為很明顯輸入和輸出如何放在方法上。 這也避免了必須返回像std :: pair那樣無法擴展的時髦結構。
可能最正確的方法是這樣的:
#include <optional>
#include <functional>
std::optional<std::reference_wrapper<const std::string>> Cat::getKittenName() const
{
Kitten* kitty = getKitty();
if (kitty)
{
return kitty->getName();
}
return std::nullopt;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.