我发现标准字符串添加速度非常慢,所以我正在寻找一些可以加速我的代码的技巧/黑客。
我的代码基本结构如下:
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 ++字符串会有帮助吗?
答案 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_string
:if
只执行一次add_to_string
,当字符串为空时,您也可以立即将其变为非空。
此外,您的data
会复制data
;这不是必需的,因为它没有被修改。接受const
added_data
引用可以加快速度。
最后,将string
从sstream
更改为sstream
可让您在循环中追加到它,而不会创建,复制和抛出{{1}}中介离开循环的每次迭代。
答案 4 :(得分:2)
请查看LLVM中使用的Twine。
Twine是一种绳索,它表示使用一个连接的字符串 二叉树,其中字符串是节点的预订顺序。自从 使用结果时,可以有效地将Twine渲染到缓冲区中, 它避免了为中间字符串生成临时值的成本 结果 - 尤其是在Twine结果永远不会发生的情况下 需要。通过显式跟踪叶节点的类型,我们也可以避免 为转换操作创建临时字符串(例如 将整数附加到字符串中。)
它可能有助于解决您的问题。
答案 5 :(得分:0)
这种做法怎么样?
这是MSVC 2010报告的DevPartner。
答案 6 :(得分:-4)
string newstring = stringA&amp; stringB;
我不认为字符串很慢,它的转换可以使它变慢 也许你的编译器可能会检查变量类型是否存在不匹配。