C ++更快的方法来添加字符串?

时间:2012-12-13 01:04:59

标签: c++ string performance

我发现标准字符串添加速度非常慢,所以我正在寻找一些可以加速我的代码的技巧/黑客。

我的代码基本结构如下:

inline void add_to_string(string data, string &added_data) {
   if(added_data.length()<1) added_data = added_data + "{";
   added_data = added_data+data;
}

int main()
{
   int some_int = 100;
   float some_float = 100.0;
   string some_string = "test";

   string added_data;
   added_data.reserve(1000*64);

   for(int ii=0;ii<1000;ii++)
   {
      //variables manipulated here
      some_int = ii;  
      some_float += ii;
      some_string.assign(ii%20,'A');
      //then we concatenate the strings!
      stringstream fragment;
      fragment<<some_int <<","<<some_float<<","<<some_string;
      add_to_string(fragment.str(),added_data);
   }
   return;
}

做一些基本的分析,我发现在for循环中使用了大量的时间。我能做些什么可以大大提高速度吗?使用c字符串而不是c ++字符串会有帮助吗?

7 个答案:

答案 0 :(得分:5)

字符串添加不是您面临的问题。由于它的设计,已知std :: stringstream很慢。在for循环的每次迭代中,stringstream负责至少2次分配和2次删除。这4个操作中的每个操作的成本可能高于字符串添加的成本。

描述以下内容并衡量差异:

std::string stringBuffer;
for(int ii=0;ii<1000;ii++)
{
  //variables manipulated here
  some_int = ii;  
  some_float += ii;
  some_string.assign(ii%20,'A');
  //then we concatenate the strings!
  char buffer[128];
  sprintf(buffer, "%i,%f,%s",some_int,some_float,some_string.c_str());
  stringBuffer = buffer;
  add_to_string(stringBuffer ,added_data);
}

理想情况下,将sprintf替换为_snprintf或编译器支持的等效项。

根据经验,默认情况下使用stringstream进行格式化,并且只要性能很重要,就切换到更快,更安全的函数,如sprintf,itoa等。

编辑:那,以及didierc所说的:added_data + = data;

答案 1 :(得分:4)

如果不在循环中调用add_to_string,则可以节省大量字符串操作。

我相信这也是一样的(虽然我不是C ++专家,也不知道stringstream究竟做了什么):

stringstream fragment;
for(int ii=0;ii<1000;ii++)
{
  //variables manipulated here
  some_int = ii;  
  some_float += ii;
  some_string.assign(ii%20,'A');
  //then we concatenate the strings!
   fragment<<some_int<<","<<some_float<<","<<some_string;
}

// inlined add_to_string call without the if-statement ;)
added_data = "{" + fragment.str();

答案 2 :(得分:3)

我看到你在added_data上使用了reserve方法,这可以避免在字符串增长时避免多次重新分配字符串。

您还应尽可能使用+=字符串运算符:

added_data += data;

我认为通过在进行连接时在临时字符串中避免来回added_data的不必要副本,上述内容可以节省一些重要的时间。

+=运算符是string::append方法的更简单版本,它只是直接在data的末尾复制added_data。由于你做了保留,单独的操作应该非常快(几乎相当于一个strcpy)。

但是为什么要经历所有这些,当你已经在使用stringstream来处理输入时?保持一切在那里开始!

stringstream类确实效率不高。

如果有必要,您可以查看stringstream class有关如何使用它的更多信息,但是使用字符串作为缓冲区的解决方案似乎可以避免类速度问题。

无论如何,除非你真的知道自己在做什么,否则不要再尝试重新实现纯C中的速度关键代码。其他一些SO帖子支持这样做的想法,但我认为最好(阅读更安全)尽可能地依赖标准库,这将随着时间的推移而得到增强,并照顾好你(或我)想不到的许多角落案例。如果您的输入数据格式是一成不变的,那么您可能会开始考虑采取这种方式,但否则就会过早优化。

答案 3 :(得分:2)

如果您使用added_data启动"{",则可以从if方法中删除add_to_stringif只执行一次add_to_string ,当字符串为空时,您也可以立即将其变为非空。

此外,您的data会复制data;这不是必需的,因为它没有被修改。接受const added_data引用可以加快速度。

最后,将stringsstream更改为sstream可让您在循环中追加到它,而不会创建,复制和抛出{{1}}中介离开循环的每次迭代。

答案 4 :(得分:2)

请查看LLVM中使用的Twine

  

Twine是一种绳索,它表示使用一个连接的字符串   二叉树,其中字符串是节点的预订顺序。自从   使用结果时,可以有效地将Twine渲染到缓冲区中,   它避免了为中间字符串生成临时值的成本   结果 - 尤其是在Twine结果永远不会发生的情况下   需要。通过显式跟踪叶节点的类型,我们也可以避免   为转换操作创建临时字符串(例如   将整数附加到字符串中。)

它可能有助于解决您的问题。

答案 5 :(得分:0)

这种做法怎么样?

这是MSVC 2010报告的DevPartner。

enter image description here

答案 6 :(得分:-4)

string newstring = stringA&amp; stringB;

我不认为字符串很慢,它的转换可以使它变慢 也许你的编译器可能会检查变量类型是否存在不匹配。

相关问题