我与某人就std::stoi
的垮台进行了愉快的交谈。说穿了,它在内部使用std::strtol
,如果报告错误则抛出。但是,根据他们的说法,std::strtol
不应为"abcxyz"
的输入报告错误,导致stoi
不投掷std::invalid_argument
。
首先,这里有两个在GCC上测试过的关于这些案件行为的程序:
strtol
stoi
它们都显示"123"
成功,"abc"
失败。
我查看标准以获取更多信息:
§21.5
Throws: invalid_argument if strtol, strtoul, strtoll, or strtoull reports that
no conversion could be performed. Throws out_of_range if the converted value is
outside the range of representable values for the return type.
总结了依赖strtol
的行为。那么strtol
呢?我在C11草案中找到了这个:
§7.22.1.4
If the subject sequence is empty or does not have the expected form, no
conversion is performed; the value of nptr is stored in the object
pointed to by endptr, provided that endptr is not a null pointer.
考虑到传递"abc"
的情况,C标准规定指向字符串开头的nptr
将存储在endptr
中,指针传入。这似乎与测试一致。此外,应返回0,如下所述:
§7.22.1.4
If no conversion could be performed, zero is returned.
之前的参考文献表示不会执行转换,因此必须返回0.这些条件现在符合stoi
抛出std::invalid_argument
的C ++ 11标准。
这对我很重要,因为我不想四处推荐stoi
作为其他字符串转换为int的更好的替代方法,或者自己使用它就好像它的工作方式一样' d期望,如果它没有将文本视为无效转换。
所以在这之后,我在某个地方出错了吗?在我看来,我有很好的证据证明这个例外被抛出。我的证明是否有效,或者std::stoi
在"abc"
给出{{1}}时不能保证抛出该异常?
答案 0 :(得分:72)
std::stoi
是否会在输入"abcxyz"
上抛出错误?是
我认为您的困惑可能来自strtol
从不报告错误这一事实,除了溢出。它可以报告没有执行转换,但这在C标准中从未被称为错误条件。
strtol
的定义类似于所有三个C标准,我将为您节省无聊的细节,但它基本上定义了一个“主题序列”,它是与实际数字对应的输入字符串的子串。以下四个条件是等效的:
*endptr != nptr
(仅在endptr
为非空时才有意义)当出现溢出时,仍然认为转换已经发生。
现在,很明显因为"abcxyz"
不包含数字,字符串"abcxyz"
的主题序列必须为空,因此不能执行转换。以下C90 / C99 / C11程序将通过实验确认:
#include <stdio.h>
#include <stdlib.h>
int main() {
char *nptr = "abcxyz", *endptr[1];
strtol(nptr, endptr, 0);
if (*endptr == nptr)
printf("No conversion could be performed.\n");
return 0;
}
这意味着当给定输入std::stoi
而没有可选的基本参数时,任何符合invalid_argument
的实现必须抛出"abcxyz"
。
std::stoi
有令人满意的错误检查?没有。如果std::stoi
表示errno == 0 && end != start && *end=='\0'
比std::strtol
之后执行完整检查std::stoi
更宽松,那么您正在与之交谈的人是正确的,因为std::stoi
会默默地删除所有字符字符串中的第一个非数字字符。
事实上,在我的脑海中,唯一一种其原生转换行为与parseInt(n, 10)
类似的语言是Javascript,即便如此,你必须强制基数为10 input | std::atoi std::stoi Javascript full check
===========+=============================================================
hello | 0 error error(NaN) error
0xygen | 0 0 error(NaN) error
0x42 | 0 0 66 error
42x0 | 42 42 42 error
42 | 42 42 42 42
-----------+-------------------------------------------------------------
languages | Perl, Ruby, Javascript Javascript C#, Java,
| PHP, C... (base 10) Python...
以避免十六进制的特殊情况数:
boost::lexical_cast<int>
注意:在处理空格和冗余+符号时,语言之间也存在差异。
我不知道有任何内置函数执行此操作,但int()
将执行您想要的操作。它特别严格,因为它甚至拒绝周围的空格,与Python的boost::bad_lexical_cast
函数不同。请注意,无效字符和溢出会导致相同的异常#include <boost/lexical_cast.hpp>
int main() {
std::string s = "42";
try {
int n = boost::lexical_cast<int>(s);
std::cout << "n = " << n << std::endl;
} catch (boost::bad_lexical_cast) {
std::cout << "conversion failed" << std::endl;
}
}
。
{{1}}