提问人:Kikadass 提问时间:9/11/2023 最后编辑:wohlstadKikadass 更新时间:9/11/2023 访问量:178
STOF、STOI、STOD 与提取器操作员
stof, stoi, stod vs extractor operator
问:
我想知道现代 C++ 中最推荐哪种方式将字符串转换为数字。双精度型、浮点型或整数型。
我遇到了 C++11,但我一直在我创建的帮助程序函数中使用提取器运算符。
但是,现在有了 C++11 // 存在。因此,我应该停止使用我的助手功能吗?我尝试研究这两种方法的不同之处,但我无法清楚地看到它们的优缺点。stof
stringstream
stof
stoi
stod
template <typename T>
bool stringToValue(const std::string& item, T& value)
{
T tmp;
std::istringstream iss(item);
if ((iss >> std::dec >> tmp).fail())
{
return false;
}
else
{
value = tmp;
return true;
}
}
我也有兴趣保持尽可能高的精度。
补充一点,我在这里找到了所有可能的选项: https://www.techiedelight.com/convert-a-string-to-a-float-in-cpp/
它们在效率或精确度方面没有进行比较。
注意:我已经看到在 C++17 中使用了 gcc 11(我相信)。我们(我和我的团队)最近迁移到了 C++17,但是,我们停留在 gcc 9.4.0。因此,可悲的是,我们不能使用那个。std::from_chars
答:
在 C++ 中有许多解析数字的方法。如需全面比较,请参阅此答案。
简而言之,所有函数都应提供相同程度的精度。 它们很可能都使用相同的基础例程在某个时间点解析浮点数。
主要区别在于它们提供的接口,以及该接口的便利性/开销。有些函数(如具有可怕的错误处理和模糊的名称),但由于不使用区域设置功能,并且不使用任何动态多态性,因此应该比流更有效。std::atoi
如有疑问,请进行基准测试以比较它们的性能。没有一个功能严格优于所有其他功能。
何时(不)使用std::sto*
单独使用系列函数是完全可以的,但它们并不能构成项目中随处可见的良好“基本效用”。它们在失败时抛出异常,并且不确定输入是否为数字(即可能失败)的“尝试解析”会很慢,因为异常处理成本非常高。std::sto*
如果你不在乎,你只需要一些简单和安全的东西(虽然不是通用的),函数就可以了。std::sto*
赞成的论点std::istringstream
流的开销很高,标头相对较大。乍一看,它们确实没有吸引力,但如果您的目标是制作“通用解析函数”,那么流比任何其他方法都更容易,因为它应该适用于所有方法。
您可以继续使用当前函数。<sstream>
>>
但是,如果 include of 的成本太高,或者您负担不起流的运行时开销,那么您必须回退到下一个最好的东西,即函数系列:<sstream>
std::strto*
bool stringToValue(const std::string& str, long& out, int base = 10) {
errno = 0;
char* end = nullptr;
out = std::strtol(str.data(), str.data() + str.size(), &end, base);
return str.data() != end && errno == 0;
}
bool stringToValue(const std::string& str, int& out, int base = 10) {
errno = 0;
char* end = nullptr; // note: there is no std::strtoi, so we use std::strtol
out = std::strtol(str.data(), str.data() + str.size(), &end, base);
return str.data() != end && errno == 0;
}
bool stringToValue(const std::string& str, float& out) {
errno = 0;
char* end = nullptr;
out = std::strtof(str.data(), str.data() + str.size(), &end, base);
return str.data() != end && errno == 0;
}
// ...
使用模板,我们可以避免复制和粘贴每个算术类型的实现。但是,替换流仍然需要付出很多努力。
评论
std::from_chars
是当今最热门的东西。所有其他替代方案都有需要解决的怪癖(主要是不完整的输入字符串验证,例如静默忽略前导空格)。您的实现也有同样的问题,此外,它还忽略了字符串末尾的垃圾。std::strtol
&std::strtod
和其他是下一个最好的东西。它们需要一些手动工作来做正确的事情,所以一定要为你的包装器编写大量的测试(字符串开头的空格、末尾的空格、末尾的垃圾、数字在两个方向上都超出范围(分别用于有符号、无符号和浮点)等)。std::from_chars
,
.
,
,
.
,
,
;
,