【发布时间】:2012-07-20 21:20:57
【问题描述】:
我与某人就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。这些条件现在符合 C++11 标准 stoi throwing std::invalid_argument。
这个结果对我来说很重要,因为我不想到处推荐 stoi 作为其他字符串到 int 转换方法的更好替代方法,或者自己使用它,就好像它按照您期望的方式工作一样,如果它没有将文本捕获为无效转换。
那么在这一切之后,我是不是哪里出错了?在我看来,我有很好的证据证明这个异常被抛出。我的证明是否有效,或者std::stoi 在给出"abc" 时不能保证抛出该异常?
【问题讨论】:
-
stoi的问题在于它在"123abc"上成功,这意味着除非您提供并检查结尾索引参数,否则它几乎没有用处。这使得它比strtol更难使用,因为您需要检查结束索引并捕获异常。 -
@chris:我希望它会像
boost::lexical_cast那样抛出异常。最常见的用例是当您想要转换整个字符串时,stoi/l/ll需要一堆样板代码来执行此操作(或将其包装在一个函数中,这也可以使用strtol完成)。sto*的实现方式更强大,但实际上并没有提供任何超过strto*的功能。 -
顺便说一下,
cin >>someInt和cin >> someString; someInt = stoi (someString);不一样。在输入123abc的情况下,第一个版本将abc留在流中,而第二个版本将其静默丢弃。 -
@interjay,是的,我明白你的意思,特别是如果这就是 boost 的作用。 “相同”是指整数的结果;我不关心比较中的流。
-
James Kanze 是个聪明人,但聪明人也会犯错。你的错误是你忘记在你的截图中检查他的名字。他的错误是他忘记了即使 abcdef 让 strtol 返回 0,strtol 也必须报告返回 0 的原因是转换失败,所以 stoi 必须抛出它的异常。但由于像 123abc 这样的情况,我仍然认为 stoi 不安全。
标签: c++ standards language-lawyer