我遇到过这个代码:
std::string str;
std::getline(std::cin, str);
std::string sub = str.substr(str.find('.') + 1);
第一反应是-这是无效代码。但经过思考,事情似乎并没有那么简单。那么它是有效的C++表达式(具有可预测的行为)吗?
PS如果不是那么清楚的话,这个问题主要和什么时候会发生有关不会在str
中找到,但不限于此,因为可能存在其他问题。
str.find('.')
返回字符串中第一个出现的字符的索引。带有一个参数的substr
返回从给定索引开始的字符串的后缀。因此,该行的作用是返回从第一个点开始的字符串尾部。因此,如果str
是"hello.good.bye"
,则sub
将是good.bye
。
但是,如果字符串实际上不包含任何点,则代码可能存在问题。它将返回整个字符串。这可能是有意的,也可能不是有意的。发生这种情况是因为如果没有点,find
将返回npos
,这是std::string::size_type
可以容纳的最大数字。加上1
,你会得到0(这就是无符号类型的行为,模2n)。
因此,代码总是具有可预测的行为。
来源http://en.cppreference.com/w/cpp/string/basic_string/npos似乎CCD_ 12。当find
不成功时,会返回该值。在这种情况下,str.substr(0)
将返回整个字符串。
这似乎是一个有效且可预测的代码。
如果您询问如果找不到.
会发生什么,您不必担心。std::string::find
然后返回std::string::npos
,标准将其定义为-1
,在添加1
之后,CCD_17溢出并使参数0
:
std::string sub = str.substr(0);
这就给了你完整的线索。我不知道这是否是想要的行为,但这肯定不是未定义的行为。
实际上,在这种特定情况下——因为包含"…无关紧要…"的字符串实际上是重要的——find()
调用找不到它要查找的内容,因此将返回std::string::npos
。然后再添加1。
npos的类型是std::string::size_type
,通常是size_t
,通常是某种类型的无符号整数
25被定义为CCD_ 26的最大可能值。
size_type
是无符号的,在最大可能值上加1会产生0。
所以你打电话给std::string::substr(0)
。这是干什么的?它会创建您调用它的整个字符串的副本,因为substr
具有起始位置和长度(默认为npos
,或"一直到结尾")。
据我所见,它是有效的,尽管它不是特别可读。
如果str
为空,则find()
方法将返回std::string::npos
。这相当于CCD_ 35所代表的最大CCD_。通过向其中添加1,您将导致整数溢出,并且它将环绕到0。这意味着substr()
方法试图使用从位置0到字符串末尾的字符创建字符串。如果str
为空,则sub
也为空。