防止函数使用const std :: string&接受0

时间:2019-11-18 06:34:30

标签: c++ string std implicit-conversion

一千个字:

#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");
}

不是一个好的解决方案。

3 个答案:

答案 0 :(得分:160)

std::string(0)有效的原因是由于0是空指针常量。所以0匹配带指针的字符串构造函数。然后,该代码将违反以下前提:不得将空指针传递给std::string

只有文字0会被解释为空指针常量,如果它是int中的运行时值,则不会出现此问题(因为过载解析会寻找一个改为int。文字1也不是问题,因为1不是空指针常量。

由于这是一个编译时问题(字面无效值),因此您可以在编译时捕获它。添加此形式的重载:

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

std::nullptr_tnullptr的类型。并且它将匹配 any 空指针常量,无论是00ULL还是nullptr。并且由于删除了该函数,因此在重载解析期间将导致编译时错误。

答案 1 :(得分:26)

一种选择是声明private的{​​{1}}重载,该重载接受一个整数参数,而不定义它。

此选项将与所有C ++标准(1998年以后)一起使用,与operator[]()之类的选项在C ++ 11中有效。

使void operator[](std::nullptr_t) = delete成为operator[]()成员将导致示例private上的可诊断错误,除非该表达式由成员函数或类的ohNo[0]使用。

如果从成员函数或类的friend中使用该表达式,则代码将编译,但是-由于未定义函数-通常,构建会失败(例如,由于函数未定义而导致的链接器错误) )。

答案 2 :(得分:2)

使用string_view有所帮助

从C ++ 17开始,我们有了std::string_view class。正是针对这种用例,即将非所有者引用传递给类似字符串的对象,传递给仅读取字符串的函数。您应该认真考虑将其用于此类运算符。

现在,testBackButton.setOnClickListener { val intent = Intent(this, ActivityThatYouWantToGo::class.java) intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK.or(Intent.FLAG_ACTIVITY_NEW_TASK) startActivity(intent) } 有其自己设置的问题(请参阅:enough string_view to hang ourselves with),但是在这里它会给您一个有用的警告。如果您替换:

std:: string_view

使用

    SayWhat& operator[](const std::string& s) {

然后使用 SayWhat& operator[](std::string_view s) { 进行编译,您将得到:

--std=c++17 -Wall