You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为自定义输出类型实现高性能的std::format风格函数

为自定义分配器字符串实现高性能std::format风格函数

我有一个带自定义分配器的字符串类型,定义如下:

struct myalloc : std::allocator<char> {};
using mystring = std::basic_string<char, std::char_traits<char>, myalloc>;

我希望实现一个std::format风格的函数来创建该类型的实例。最初我通过迭代器实现:

template<class ...Args> constexpr mystring
myformat(std::format_string<Args...> fmt, Args &&...args)
{
  mystring ret;
  std::format_to(std::back_inserter(ret), fmt, std::forward<Args>(args)...);
  return ret;
}

但这个实现性能极差:在AMD EPYC CPU上,用std::format格式化256字节字符串256次耗时约60ns,而myformat耗时790ns,慢了13倍!gcc 14.1/libstdc和clang 18.1/libc++下结果类似。

我的问题是:如何利用格式化库实现自定义输出类型的格式化函数,同时避免如此巨大的性能损耗?


更新:
根据Miles Budnek的建议,使用std::formatted_size预分配空间后,性能有所提升:

template<class ...Args> constexpr mystring
myformat(std::format_string<Args...> fmt, Args &&...args)
{
  mystring ret(std::formatted_size(fmt, std::forward<Args>(args)...), '\0');
  std::format_to(ret.data(), fmt, std::forward<Args>(args)...);
  return ret;
}

但该实现仍耗时134ns,比std::format慢两倍以上。另外,我希望将方案推广到vformat,但std::formatted_size没有对应的v版本,也无法对format_args执行类似std::apply的操作。


更新2:
我实现了一个仅统计字符数的伪迭代器,以此实现了vformat的等效版本myvformat,性能甚至优于调用std::formatted_size的版本,重新实现后的代码如下:

struct counter {
  std::size_t n{};
  using difference_type = long;
  auto operator*() const { return std::ignore; }
  counter &operator++() { ++n; return *this; }
  counter operator++(int) { return counter{n++}; }
};
static_assert(std::output_iterator<counter, char>);

constexpr mystring
myvformat(std::string_view fmt, std::format_args args)
{
  counter c;
  c = std::vformat_to(c, fmt, args);
  mystring ret(c.n, '\0');
  std::vformat_to(ret.data(), fmt, args);
  return ret;
}

template<class ...Args> constexpr mystring
myformat(std::format_string<Args...> fmt, Args &&...args)
{
  return myvformat(fmt.get(),
           std::make_format_args(std::forward<Args>(args)...));
}

此时myformat耗时85ns,而std::vformat输出到std::string耗时60ns,性能有所提升但仍有明显差距。相比之下,调用std::format后将结果拷贝到mystring耗时72ns,但出于安全考虑,实际应用中不能采用这种方式——内容不能存放在普通堆中。


内容的提问来源于stack exchange,提问作者user3188445

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 19:07:05