【问题标题】:C++17 Purpose of std::from_chars and std::to_chars?C++17 std::from_chars 和 std::to_chars 的用途?
【发布时间】:2023-03-23 09:58:01
【问题描述】:

在 C++17 之前,存在多种将整数、浮点数和双精度数与字符串转换的方法。例如,std::stringstreamstd::to_stringstd::atoistd::stoi 和其他可能已用于完成这些任务。对此,有很多帖子讨论这些方法之间的差异。

不过,C++ 17 现在引入了std::from_charsstd::to_chars。为此,我想知道引入另一种与字符串相互转换的方法的原因。

首先,这些新功能与以前的方法相比有哪些优势和功能?

不仅如此,这种新的字符串转换方法有什么明显的缺点吗?

【问题讨论】:

  • 我认为它们在处理语言环境、内存分配和异常行为的方式上有所不同,但我手头没有详细信息。
  • 来自注释 "...与 C++ 和 C 库中的其他解析函数不同,std::from_chars 与语言环境无关、不分配和不抛出......" 来源:en.cppreference.com/w/cpp/utility/from_chars
  • 一个字:速度!!!!
  • 现在,要是 GCC 和 Clang 能完成它们的实现就好了!

标签: c++ string language-lawyer c++17


【解决方案1】:

所有这些预先存在的方法都必须基于所谓的语言环境工作。语言环境基本上是一组格式化选项,它们指定例如,哪些字符被视为数字,小数点使用什么符号,使用千位分隔符等等。然而,很多时候,你并不真正需要它。例如,如果您只是读取 JSON 文件,您知道数据是以特定方式格式化的,则没有理由每次看到 '.' 是否应该是小数点时查找一个。 <charconv> 中引入的新函数基本上是硬编码的,可以根据为默认 C 语言环境布置的格式来读取和写入数字。无法更改格式,但由于格式不必灵活,它们可以非常快……

【讨论】:

    【解决方案2】:

    std::stringstream是重量级冠军。它考虑了流的imbued locale 之类的东西,它的功能在格式化操作期间涉及constructing a sentry object 之类的东西,以处理与异常相关的问题。 C++ 库中的格式化输入和输出操作以being heavyweight, and slow 着称。

    std::to_string 没有std::istringstream 密集,但它仍然返回std::string,其构造可能涉及动态分配(现代短字符串优化技术不太可能,但仍然可能)。并且,在大多数情况下,编译器仍然需要在调用站点生成所有冗长的语句,以支持 std::string 对象,包括其析构函数。

    std::to_chars 旨在尽可能减少占用空间。您提供缓冲区,std::to_chars 除了以特定格式将数值实际格式化到缓冲区之外,几乎没有做任何特定于语言环境的考虑,唯一的开销是确保缓冲区足够大。使用std::to_chars的代码不需要做任何动态分配。

    std::to_chars 在格式化选项方面也更加灵活,尤其是浮点值。 std::to_string 没有格式化选项。

    std::from_chars 同样是一个轻量级解析器,不需要进行任何动态分配,也不需要牺牲任何电子来处理语言环境问题或流操作的开销。

    【讨论】:

    • std::to_string 也观察当前语言环境。所以我会说它不是更少,而是就格式而言实际上更灵活......
    【解决方案3】:

    to/from_chars 被设计为基本的字符串转换函数。与替代品相比,它们有两个基本优势。

    1. 它们的重量要轻得多。他们从不分配内存(您为他们分配内存)。他们从不抛出异常。他们也从不查看语言环境,这也提高了性能。

      基本上,它们的设计是不可能在 API 级别拥有更快的转换函数。

      这些函数甚至可以是 constexpr(它们不是,虽然我不确定为什么),而更重量级的分配和/​​或抛出版本则不能。

    2. 他们有明确的往返保证。如果您将 float/double 转换为字符串(没有指定精度),则 需要 来实现它,以便获取确切的字符序列并将其转换回 float/double 将产生二进制相同值。你不会从snprintfstringstreamto_string/stof 那里得到保证。

      这种保证只有在 to_charsfrom_chars 调用使用相同的实现时才有效。因此,您不能期望通过 Internet 将字符串发送到可能使用不同标准库实现编译的其他计算机并获得相同的float。但它确实为您提供了计算机上的序列化保证。

    【讨论】:

    • 为什么to/from_chars 没有跨实现的往返保证?如果我们假设 ieee754,那么我们是否获得跨实现的往返保证?
    • @Justin:即使您假设 IEEE(标准没有),您仍然必须准确指定四舍五入的工作方式。这可能会妨碍特定硬件的更高性能实现。
    • 这个往返转换属性是我们多年来所需要的。但是,当您跨行使用 XML 或 JSON 交换时,仅保证处理自己的实现结果会有点令人沮丧。我分析了“from_chars”,它每次都比使用 Boost 的 lexical_cast 和经典语言环境设置快大约 10 倍(因为一些库在没有恢复它的情况下更改它,从而破坏了任何与语言环境无关的存储)。
    • @gast128:问题是,您始终可以将特定实现提取到您的应用程序中(或使用公开可用的实现),这将为您带来所有性能优势,同时保持相同的 API。跨度>
    猜你喜欢
    • 2021-06-08
    • 2018-08-12
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多