[英]Prevent function taking const std::string& from accepting 0
值得一千字:
#include<string>
#include<iostream>
class SayWhat {
public:
SayWhat& operator[](const std::string& s) {
std::cout << s << "\n";
return *this;
}
};
int main() {
SayWhat ohNo;
// ohNo[1]; // Does not compile. Logic prevails.
ohNo[0]; // you didn't! this compiles.
return 0;
}
將數字 0 傳遞給接受字符串的括號運算符時,編譯器不會抱怨。 相反,這會在進入方法之前編譯並失敗:
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
以供參考:
> g++ -std=c++17 -O3 -Wall -Werror -pedantic test.cpp -o test && ./test
> g++ --version
gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)
我猜
編譯器隱式使用std::string(0)
構造函數進入該方法,這會產生同樣的問題(谷歌上述錯誤),沒有充分的理由。
問題
有沒有辦法在 class 端解決這個問題,所以 API 用戶感覺不到這個並且在編譯時檢測到錯誤?
也就是說,添加一個重載
void operator[](size_t t) {
throw std::runtime_error("don't");
}
不是一個好的解決方案。
std::string(0)
有效的原因是0
是 null 指針常量。 所以 0 匹配帶有指針的字符串構造函數。 然后代碼運行與不能將 null 指針傳遞給std::string
的前提條件相沖突。
只有文字0
會被解釋為 null 指針常量,如果它是int
中的運行時值,則不會遇到此問題(因為重載解析將改為尋找int
轉換)。 文字1
也不是問題,因為1
不是 null 指針常量。
由於這是一個編譯時問題(文字無效值),您可以在編譯時捕獲它。 添加此表單的重載:
void operator[](std::nullptr_t) = delete;
std::nullptr_t
是nullptr
的類型。 它將匹配任何null 指針常量,無論是0
、 0ULL
還是nullptr
。 並且由於function被刪除,在重載解析時會造成編譯時錯誤。
一種選擇是聲明operator[]()
的private
重載,它接受一個整數參數,並且不定義它。
此選項適用於所有 C++ 標准(1998 年起),不像void operator[](std::nullptr_t) = delete
等選項在 C++11 中有效。
將operator[]()
設為private
成員將導致示例ohNo[0]
出現可診斷錯誤,除非該表達式由成員 function 或 class 的friend
使用。
If that expression is used from a member function or friend
of the class, the code will compile but - since the function is not defined - generally the build will fail (eg a linker error due to an undefined function).
從 C++17 開始,我們有std::string_view
class 。 它完全適用於這種用例,將非擁有的對類字符串對象的引用傳遞給只讀取字符串的函數。 您應該認真考慮將其用於此類運算符。
現在, std:: string_view
有它自己的設置問題(請參閱:足夠的string_view
to hang 我們自己),但在這里它會給你一個有用的警告。 如果您更換:
SayWhat& operator[](const std::string& s) {
和
SayWhat& operator[](std::string_view s) {
你用--std=c++17 -Wall
編譯,你得到:
<source>: In function 'int main()':
<source>:16:11: warning: null argument where non-null required (argument 2) [-Wnonnull]
16 | ohNo[0]; // you didn't! this compiles.
| ^
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.