gpt4 book ai didi

stof, stoi, stod vs extractor operator(stof、stoi、stod与提取器操作员)

转载 作者:bug小助手 更新时间:2023-10-22 18:18:46 27 4
gpt4 key购买 nike



I was wondering which way is the most recommended one in modern C++ to convert a string to a number. Either double, float or integer.


I came across the C++11 stof but I have been using the extractor operator in stringstream instead within a helper function I created.
However, now with C++11 stof/stoi/stod exist. Therefor, should I stop using my helper function? I have tried researching the differents of both methods, but I cannot clearly see the pros and cons of them.


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;
}
}

I am also interested in keeping as much precision as possible.

我也有兴趣保持尽可能多的准确性。


Just to add, I found all the possible options here:
https://www.techiedelight.com/convert-a-string-to-a-float-in-cpp/

我在这里找到了所有可能的选项:https://www.techiedelight.com/convert-a-string-to-a-float-in-cpp/


They are not compared in terms of efficiency or precission.

它们没有在效率或精度方面进行比较。


NOTE: I have seen std::from_chars used in C++17 with gcc 11 (I believe). We (My team and I) have recently moved to C++17, However, we are stuck at gcc 9.4.0. Therefor, we cannot use that one, sadly.


更多回答

std::from_chars is the hottest thing nowadays. All other alternatives have quirks (mostly incomplete input string validation, such as silently ignoring leading whitespace) that need to be worked around. Your implementation has the same issue, and additionally it ignores junk at the end of string.

std::from_chars是当今最热门的东西。所有其他替代方案都有一些需要解决的怪癖(大多数是不完整的输入字符串验证,例如无声地忽略前导空格)。您的实现也有同样的问题,而且它忽略了字符串末尾的垃圾。

std::strtol & std::strtod and others are the next best thing. They need some manual work to do the right thing, so make sure to write a lot of tests for your wrapper (whitespace at the beginning of string, whitespace at the end, junk at the end, numbers being out of range in both directions (separately for signed, unsigned, and floating-point), etc).

std::strtol std::strtod和其他东西是下一个最好的东西。他们需要一些手工工作来做正确的事情,所以一定要为包装器写很多测试(字符串开头的空白、结尾的空白、末尾的垃圾、数字在两个方向上都超出范围(分别用于有符号、无符号和浮点),等等)。

Note that std::from_chars doesn't use locale if that's important to your application. The first question to ask is does the performance really matter? Is your program currently spending significant time parsing numbers? If not then stick with your already working solution. All the parsers have the same precision (they probably even call the same underlying conversion routines)

请注意,如果std::from_chars对您的应用程序很重要,那么它不使用区域设置。要问的第一个问题是表演真的重要吗?您的程序当前是否花费大量时间解析数字?如果没有,那就坚持你已经有效的解决方案。所有的解析器都具有相同的精度(它们甚至可能调用相同的底层转换例程)

@AlanBirtles Off-topic: I don't remember a single time when locale-dependent number parsing was useful. The decimal point in my locale is , rather than ., but having a user-facing application only understand , is silly. The only sane option is to replace ,->. before parsing regardless of locale (in user-facing apps), or just don't support , altogether (in text file formats). Microsoft tried to embrace the whole locale thing, and now Excel can't directly open CSV files in my locale, since they switch from , to ; as field separator when , is already taken as decimal point.

@AlanBirtles Off主题:我不记得任何一次依赖于区域设置的数字解析有用。我的区域设置中的小数点是,而不是。,但让面向用户的应用程序只理解是愚蠢的。唯一明智的选择是替换,->。在解析之前,无论语言环境如何(在面向用户的应用程序中),或者完全不支持(在文本文件格式中)。微软试图接受整个区域设置,现在Excel无法直接在我的区域设置中打开CSV文件,因为它们从、切换到;作为字段分隔符时,已被用作小数点。

See also stackoverflow.com/q/7663709/5740428; but the answers there also don't really compare the different methods

另请参见stackoverflow.com/q/7663309/5740428;但那里的答案也不能真正比较不同的方法

优秀答案推荐

There are many methods of parsing numbers in C++. For a comprehensive comparison, see this answer.


In short, all the functions should offer the same degree of precision.
Chances are that they all use the same underlying routine for parsing floating point numbers at some point.

简而言之,所有函数都应该提供相同程度的精度。它们很可能在某个时刻都使用相同的底层例程来解析浮点数。


The main difference is the interface they provide, and what convenience/overhead that interface has. Some functions like std::atoi have terrible error handling and obscure names, but should be more efficient than streams due to not using locale features, and not using any dynamic polymorphism.

主要区别在于它们提供的接口,以及接口的便利性/开销。像std::atoi这样的一些函数具有糟糕的错误处理和模糊的名称,但由于不使用区域设置功能,也不使用任何动态多态性,因此应该比流更高效。


When in doubt, benchmark to compare their performance. There is no single function that is strictly better than all the others.

当有疑问时,用基准来比较他们的表现。没有任何一个函数比所有其他函数都好。


When (not) to use std::sto*


It's perfectly fine to use std::sto* family functions on their own, but they don't make for a good "fundamental utility" that is used everywhere in the project. They throw exceptions on failure, and "attempted parsing" where you're not sure whether the input is a number (i.e. failure is likely) would be slow because exception handling is very costly.

单独使用std::sto*族函数是完全可以的,但它们并不能成为项目中随处使用的良好的“基本实用程序”。它们在失败时抛出异常,而在不确定输入是否为数字(即可能失败)的情况下“尝试解析”会很慢,因为异常处理成本很高。


If you don't care and you just need something simple and safe (although not generic), std::sto* functions are fine.

如果你不在乎,只需要一些简单安全的东西(尽管不是通用的),std::sto*函数就可以了。


The argument in favor of std::istringstream


Streams have high overhead and the header <sstream> is relatively large. They are really unattractive at first glance, but if your goal is to make a "universal parsing function", then streams make this easier than any other method because >> is supposed to work for everything.
You could keep using your current function.

流具有较高的开销,并且报头<sstream>相对较大。乍一看,它们确实没有吸引力,但如果你的目标是制作一个“通用解析函数”,那么流比任何其他方法都更容易实现,因为>>应该适用于所有方法。你可以继续使用你当前的功能。


However, if the include of <sstream> is too expensive, or you can't afford the run-time overhead that streams have, then you have to fall back onto the next best thing, the std::strto* family of functions:

但是,如果 的include太昂贵,或者您负担不起流的运行时开销,那么您就必须回到下一个最好的东西上,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;
}

// ...

With templates, we could avoid copying and pasting an implementation for every single arithmetic type. However, it's still going to take a lot of effort to replace streams.

使用模板,我们可以避免复制和粘贴每个算术类型的实现。然而,替换流仍然需要付出很多努力。


更多回答

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com