stof、stoi、stod 与提取器操作员

问题描述 投票:0回答:1

我想知道现代 C++ 中最推荐哪种方式将字符串转换为数字。双精度型、浮点型或整数型。

我遇到了 C++11

stof
,但我一直在
stringstream
中使用提取器运算符,而不是在我创建的辅助函数中使用。 然而,现在 C++11
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/

它们不是在效率或精度方面进行比较。

注意: 我见过

std::from_chars
在 C++17 和 gcc 11 中使用(我相信)。我们(我和我的团队)最近转向了 C++17,但是,我们仍停留在 gcc 9.4.0。因此,遗憾的是我们不能使用那个。

c++ performance type-conversion precision
1个回答
0
投票

C++中有很多解析数字的方法。要进行全面比较,请参阅此答案

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

主要区别在于它们提供的接口,以及该接口有哪些便利/开销。像

std::atoi
这样的一些函数具有糟糕的错误处理和晦涩的名称,但由于不使用区域设置功能,并且不使用任何动态多态性,因此应该比流更有效。

如有疑问,请进行基准比较。

何时(不)使用
std::sto*

单独使用

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

如果你不在乎并且只需要一些简单和安全的东西(尽管不是通用的),

std::sto*
功能就可以了。

支持
std::istringstream

的论点

流开销较高,标头

<sstream>
也比较大。乍一看它们确实没有吸引力,但如果您的目标是创建“通用解析函数”,那么流比任何其他方法都更容易,因为
>>
应该适用于所有情况。 您可以继续使用当前的功能。

但是,如果包含

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

// ...

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

© www.soinside.com 2019 - 2024. All rights reserved.