std::stoi
的缺陷。坦率地说,它在内部使用std::strtol
,并且如果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。这些条件现在符合C++11标准,使得 stoi
抛出 std::invalid_argument
异常。
对我来说,这个结果很重要,因为我不想去推荐使用 stoi
作为字符串转换成整数的更好选择,或者像它按照你所期望的那样工作一样使用它,如果它没有将文本捕获为无效转换。
经过所有这些后,我是否有什么地方做错了?在我的看来,我有这个异常被抛出的充分证据。我的证明是否有效,或者当给定 "abc"
时,std::stoi
是否保证会抛出该异常?
stoi
的问题在于它可以成功地将"123abc"
转为整数,这意味着它大多数时候都是无用的,除非你提供并检查结束索引参数。这使得它比strtol
更难使用,因为你需要同时检查结束索引和捕获异常。 - interjayboost::lexical_cast
一样抛出异常。最常见的用例是当您想要转换整个字符串时,而stoi/l/ll
需要大量样板代码来完成这项工作(或将其包装在函数中,也可以使用strtol
完成)。sto*
的实现方式更加强大,但与strto*
相比并没有提供任何优势。 - interjay