c++ - 防止函數使用const std:: string&接受0




implicit-conversion (2)

值一千字:

#include<string>
#include<iostream>

class SayWhat {
    public:
    SayWhat& operator[](const std::string& s) {
        std::cout<<"here\n"; // To make sure we fail on function entry
        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) 構造函數輸入該方法,由於沒有充分的理由,這會產生相同的問題(谷歌上述錯誤)。

無論如何,有沒有在類方面解決此問題,因此API用戶感覺不到這一點,並且在編譯時檢測到錯誤?

也就是說,添加重載

void operator[](size_t t) {
    throw std::runtime_error("don't");
}

不是一個好的解決方案。


一種選擇是聲明一個 operator[]()private 重載,該重載接受一個整數參數,而不定義它。

此選項可與所有C ++標準(1998年以後)一起使用,不同於 void operator[](std::nullptr_t) = delete 類的選項在C ++ 11中有效。

operator[]() ohNo[0] private 成員會在示例 ohNo[0] 上引起可診斷的錯誤,除非該表達式由成員函數或類的 friend 使用。

如果從成員函數或類的 friend 使用該表達式,則將編譯代碼,但是-由於未定義函數-通常,構建將失敗(例如,由於未定義函數而導致的鏈接器錯誤)。


std::string(0) 有效的原因是由於 0 是空指針常量。 因此,它與採用指針的構造函數匹配。 然後,它違反了一個前提條件,即不能將空指針傳遞給 std::string 。 只有立即數 0 會被解釋為空指針常量,如果它是 int 的運行時值,那麼您就不會有這個問題(因為過載解析會改為查找 int 轉換)。 文字 1 也不是問題,因為 1 不是空指針常量。

由於這是一個編譯時問題(字面無效值),因此您可以在編譯時捕獲它。 添加此形式的重載:

void operator[](std::nullptr_t) = delete;

std::nullptr_tnullptr 的類型。 並且它將匹配 任何 空指針常量,可以是 0ULLnullptr 。 並且由於刪除了該函數,因此在重載解析期間將導致編譯時錯誤。





implicit-conversion