Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 防止函数采用常量std::string&;从接受0开始_C++_String_Std_Implicit Conversion - Fatal编程技术网

C++ 防止函数采用常量std::string&;从接受0开始

C++ 防止函数采用常量std::string&;从接受0开始,c++,string,std,implicit-conversion,C++,String,Std,Implicit Conversion,千言万语: #include<string> #include<iostream> class SayWhat { public: SayWhat& operator[](const std::string& s) { std::cout << s << "\n"; return *this; } }; int main() { SayWhat

千言万语:

#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;
}
供参考:

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

不是一个好的解决方案。

原因
std::string(0)
是有效的,因为
0
是一个空指针常量。因此0与使用指针的字符串构造函数匹配。然后,代码运行时违反了不能向
std::string
传递空指针的前提条件

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

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

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

std::nullptr\u t
nullptr
的类型。它将匹配任何空指针常量,无论是
0
0ULL
还是
nullptr
。由于函数被删除,在重载解析过程中会导致编译时错误。

一个选项是声明
运算符[](
重载,该重载接受整型参数,而不定义整型参数

此选项将适用于所有C++标准(1998 on),与“代码>空格操作符[](STD::NulLpTr.t)=删除< /代码>等选项不同,这些选项从C++ 11中有效。

使
运算符[]()
成为
私有成员将在示例
ohNo[0]
上导致可诊断错误,除非该表达式由类的成员函数或
朋友使用

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

使用字符串视图会有所帮助(有些) 从C++17开始,我们有了。它正是为了这个用例而设计的,将非所有权引用传递给类似字符串的对象,传递给只读取字符串的函数。对于这种运算符,你应该认真考虑使用它。

现在,
std::string_view
有自己的设置问题(请参见:),但这里它会给您一个有用的警告。如果更换:

    SayWhat& operator[](const std::string& 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.
      |           ^
:在函数“int main()”中:
:16:11:警告:null参数,其中需要非null(参数2)[-Wnonnull]
16 | ohNo[0];//你没有!这是一份汇编。
|           ^

编译后的代码,在Visual studio中ohNo[0]处引发异常,异常“0xC0000005:访问冲突读取位置0x00000000”声明一个
运算符[](
的私有重载,该重载接受
int
参数,但不定义它。@Peter尽管注意到这是链接器错误,这仍然比我所拥有的要好。@kabanus在上面的场景中,这将是一个编译器错误,因为操作符是私有的!链接器错误仅在类内调用时发生…@Peter这在没有C++11可用的情况下尤其有趣–这些情况甚至在今天也存在(实际上我正在处理一个项目,我缺少了很多新功能…。这是目前为止最好的解决方案,完全忘记了我可以重载空指针。在Visual Studio中,甚至“ohNo[0]”引发空值异常。这是否意味着std::string类的特定于实现?@pmp抛出的内容(如果有的话)是特定于实现的,但关键是字符串在所有这些内容中都是空指针。使用此解决方案,您将无法到达异常部分,它将在编译时检测到。@ PMP-通过空指针到<代码> STD::String < /C>的构造函数是C++标准不允许的。这是未定义的行为,所以MSVC可以做任何它喜欢的事情(比如抛出一个异常)。我认为这将是只读情况下更好的解决方案,比如我的模拟示例,甚至可能是任何
常量字符串&
函数参数。我认为,在这些情况下,大多数“悬而未决”的问题都是没有意义的(不需要刻意打破某些东西)。
    SayWhat& operator[](std::string_view s) {
<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.
      |           ^