首页 > 解决方案 > 防止采用 const std::string& 的函数接受 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)构造函数进入方法,这会产生同样的问题(谷歌上面的错误),没有充分的理由。

问题

无论如何要在类方面解决这个问题,所以 API 用户不会感觉到这一点,并且在编译时检测到错误?

也就是说,添加一个重载

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

不是一个好的解决方案。

标签: c++stringstdimplicit-conversion

解决方案


原因std::string(0)是有效的,是由于0是一个空指针常量。所以 0 匹配带有指针的字符串构造函数。然后代码与不能将空指针传递给std::string.

只有文字0会被解释为空指针常量,如果它是运行时值,则不会出现此问题(因为重载解决方案将改为int寻找转换)。int字面量也不是1问题,因为1它不是空指针常量。

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

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

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


推荐阅读