减少"const char*"和"const std::string&"参数的过载

Reducing overloading on both "const char*" and "const std::string&" arguments

本文关键字:const 参数 std char 减少 string      更新时间:2023-10-16

问题

我发现std::basic_stringc_str成员函数很难看,但同时我不希望创建大量临时std::basic_string的性能受到影响。

示例

例如,给定以下函数签名:

void foo(const char* s);
void bar(const std::string& s);

显式调用c_str

如果我有一个std::string,我必须在调用站点显式调用c_str成员函数才能调用foo,这有点难看。

std::string s = "...";
foo(s.c_str()); // Yuck! Ugly!

创建临时性

但是,如果我已经有了const char*,编译器需要创建一个临时std::string来调用bar可能会影响性能。

const char* s = "...";
bar(s); // Yuck! Potentially a performance hit!

过载

另一方面,我可以为两者提供重载,并将结果从一个转发到另一个,但由于懒惰,我不想编写超出需要的代码。

void baz(const char* s);
// Yuck! Carpal tunnel syndrome imminent.
inline void baz(const std::string& s)
{
   baz(s.c_str());
}

要求

所以我认为有一个更好的选择:

  1. 不需要写入重载
  2. 函数签名不是很难看吗
  3. 不会影响演出
  4. 不会涉及在函数中编写(太多(额外的代码

可能的替代方案

我原以为boost::string_ref在这方面会对我有所帮助,但它缺乏一种转换为const char*的廉价方法。

解决方案

所以我想创建一个新的类来帮助我实现这一点,就像这样:

class c_str
{
public:
   c_str(const char* s)
      : s(s)
   {
   }
   c_str(const std::string& s)
      : s(s.c_str())
   {
   }
   operator const char*() const
   {
      return s;
   }
private:
   const char* s;
};
void qux(const c_str& s)
{
   std::string s1 = s;
   const char* s2 = s;
   std::cout << s;
}

用法

foo("s1");
const char* s2 = "s2";
foo(s2);
const std::string s3 = "s3";
foo(s3);
foo(std::string("s4"));

类似的类是否已经存在?或者还有更好的选择吗?

编辑:如果有许多类似字符串的参数,问题会很快升级。在我的例子中只有一个,但可以有很多。

不要低估现代编译器的威力。在考虑优化这样的代码之前,一定要先进行评测。

IMO,在编写优化代码之前,最好先编写干净、可维护和安全的代码,尽量比库更"智能"。

如果您必须对字符串(char*或std::string(操作进行优化,因为您的应用程序的目标是处理字符串(大型字符串数据集(,那么您可能需要为您的特定用途找到其他类型的容器(和/或字符串池…(。

实际上,string_ref正是为了解决这个问题。

char const*的问题是没有嵌入长度;C字符串在第一次出现NUL字符((时结束,这意味着无论何时使用CCD_。

另一方面,string_ref嵌入了char const*显式长度,因此适用于包括NUL的整个字符集。因此,如果性能很重要,解决方案是使用string_ref

当然,性能是否重要(在这个呼叫站点(,或者你是否真的从一开始就得到了char const*,这完全是另一回事。通常,在C++中,char const*是一个奇怪的地方(您可以使用std::string const常量(,而string_ref唯一真正感兴趣的地方是解析(因为大量的substr调用可能会对性能产生影响,而仅仅碰撞一个整数是很便宜的(。