无需宏即可更快地追加常量字符串

Faster constant string appending without macro

本文关键字:追加 常量 字符串      更新时间:2023-10-16

所以在组合字符串时,通常有常量组件,例如:

std::string s;
s += initial_string;
s += "const string";
s += terminating_string;

这只是一个演示,字符串操作可能更加复杂和深入。 因此,在执行 const 部分时,实现最终"不知道"长度并有效地对其进行strlen()。 显然,这是一种浪费,因为长度在编译时是已知的。 我已经测试过用这个替换 const 字符串部分要快得多(无论出于何种原因,在 x64 中要快得多(:

s.append("const string",12);

实际计算字符很烦人、耗时且容易出错,所以这样更好一点:

s.append("const string",sizeof("const string")-1);

这仍然有点容易出错(即更改第一部分但忘记更改第二部分(,因此宏可以帮助:

#define strnsizeof(s) s,sizeof(s)-1
s.append(strnsizeof("const string"));

问题1:有人有更好/更清洁的解决方案吗?

还有一个扩展的字符串类,我在其中使用 << 运算符来连接字符串和各种其他对象类型。 这里有类似的问题,这很好很干净(对我来说(:

s << initial_string << "const string" << terminating_string;

当我有一个用于我自己的对象类型(长度是一个组件(的运算符时,追加操作既快速又简单,但是当它再次在此处获得const char *时,即使它在编译时是常量,我也不会得到长度。 因此,我可以通过创建一个小结构来加快速度,该结构采用如下行const char *和长度:

s << initial_string
    << MyStr::ConstBuf(strnsizeof("const string"))
    << terminating_string;

男孩是不是越来越丑了。 所以我也可以将其宏化,例如:

#define MyStrConst(s) MyStr::ConstBuf(s,sizeof(s)-1)
s << initial_string
    << MyStrConst("const string")
    << terminating_string;

更好,但不是很好。

问题2:有人有比封装常量字符串更好/更干净的解决方案吗?

对问题的评论产生了如下所示的模板:

template<size_t SZ> std::string& operator<<( std::string &s, const char(&arr)[SZ] ) {
    s.append( arr, SZ-1 );
    return s;
}
因此,在

执行以下操作时,不会使用模板s += "const string"而是使用模板:

s << "const string"

此外,我能够更新我的扩展字符串类,以便以下内容也利用模板来获取常量大小:

s << initial_string << "const string" << terminating_string;

编辑:这不能按预期工作:

typedef struct { char buffer[32]; } ST;
ST st = { "1234" };
s << st.buffer;  // results in s with size 31!

这可以通过非常量模板来解决,例如:

template<size_t SZ> std::string& operator<<( std::string &s, char(&arr)[SZ] ) {
    s.append( arr ); // NOTE not using SZ here so a strlen happens
    return s;
}

所以现在:

s << st.buffer;  // results in s with size 4

除了:

const ST cst = &st;
s << cst.buffer;  // results in s with size 31 again...

正如您所期望的那样,当buffer处于class中时,同样的问题。

写信给你的编译器制造商,问他们为什么不针对这种情况进行优化。然后,希望他们将常量字符串串联添加到优化列表中,并且每个人的代码都会更快,而无需执行任何操作!

这将是我最喜欢的解决方案。

那只是:

const std::string const_string("const string");
std::string s;
s += initial_string;
s += const_string;
s += terminating_string;

我无法访问MSVC编译器。保留足够大的缓冲区会提高性能吗?

类似的东西

#include <iostream>
#include <string>
using namespace std;
string fast_concat(string s, const string& terminating_string) {
  static const string const_string("const string");
  s.reserve(s.size() + const_string.size() + terminating_string.size());
  s.append(const_string);
  s.append(terminating_string);
  return s;
}
int main() {
  cout << fast_concat("initial_string, ", ", terminating string") << endl;
}

(我希望在按值捕获第一个参数以及返回结果时移动。

以下是使用模板在编译时获得strlen的方法

#include <iostream>
#include <string>
using namespace std;
template <size_t N>
void concat_char_array(string& s, const char (&array)[N]) {
    s.append(array, N-1);
}
string fast_concat(string s, const string& terminating_string) {
  concat_char_array(s, "const string");
  s.append(terminating_string);
  return s;
}
int main() {
  cout << fast_concat("initial string, ", ", terminating string") << endl;
}

它应该和宏一样快。