gpt4 book ai didi

c++ - std::string 的性能优化

转载 作者:太空狗 更新时间:2023-10-29 20:37:53 27 4
gpt4 key购买 nike

当我在我的应用程序中进行一些性能测试时,我注意到以下代码 (Visual Studio 2010) 有所不同。

较慢的版本

while(heavyloop)
{
if(path+node+"/" == curNode)
{
do something
}
}

这将导致为生成的结果字符串生成一些额外的 mallocs。

为了避免这些mallocs,我改成了下面的方式:

std::string buffer;
buffer.reserve(500); // Big enough to hold all combinations without the need of malloc

while(heavyloop)
{
buffer = path;
buffer += node;
buffer += "/";

if(buffer == curNode)
{
do something
}
}

虽然与第一个版本相比第二个版本看起来有点笨拙,但它仍然具有足够的可读性。不过我想知道的是,这种优化是否是对编译器的一部分的疏忽,或者是否总是必须手动完成。因为它只改变了分配的顺序,所以我希望编译器也能自己弄清楚。另一方面,必须满足某些条件才能真正使其成为优化,这可能不一定完全满足,但如果不满足这些条件,代码至少会与第一个版本一样好。在这方面,较新版本的 Visual Studio 是否更好?

显示差异的更完整版本 (SSCE):

std::string gen_random(std::string &oString, const int len)
{
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";

oString = "";

for (int i = 0; i < len; ++i)
{
oString += alphanum[rand() % (sizeof(alphanum) - 1)];
}

return oString;
}

int main(int argc, char *argv[])
{
clock_t start = clock();
std::string s = "/";
size_t adds = 0;
size_t subs = 0;
size_t max_len = 0;

s.reserve(100000);

for(size_t i = 0; i < 1000000; i++)
{
std::string t1;
std::string t2;
if(rand() % 2)
{
// Slow version
//s += gen_random(t1, (rand() % 15)+3) + "/" + gen_random(t2, (rand() % 15)+3);

// Fast version
s += gen_random(t1, (rand() % 15)+3);
s += "/";
s += gen_random(t2, (rand() % 15)+3);
adds++;
}
else
{
subs++;
size_t pos = s.find_last_of("/", s.length()-1);
if(pos != std::string::npos)
s.resize(pos);

if(s.length() == 0)
s = "/";
}

if(max_len < s.length())
max_len = s.length();
}
std::cout << "Elapsed: " << clock() - start << std::endl;
std::cout << "Added: " << adds << std::endl;
std::cout << "Subtracted: " << subs << std::endl;
std::cout << "Max: " << max_len << std::endl;

return 0;
}

在我的系统上,两者之间有大约 1 秒的差异(这次使用 gcc 进行了测试,但似乎与 Visual Studio 没有任何显着差异):

Elapsed: 2669
Added: 500339
Subtracted: 499661
Max: 47197

Elapsed: 3417
Added: 500339
Subtracted: 499661
Max: 47367

最佳答案

你的慢版本可能被重写为

while(heavyloop)
{
std::string tempA = path + node;
std::string tempB = tempA + "/";

if(tempB == curNode)
{
do something
}
}

是的,它不是一个完整的模拟,但可以使临时对象更加可见。

看到两个临时对象:tempAtempB。它们的创建是因为 std::string::operator+始终生成新的 std::string 对象。这就是 std::string 的设计方式。编译器将无法优化此代码。

C++ 中有一种技术叫做 expression templates解决这个问题,但同样,它是在库级别完成的。

关于c++ - std::string 的性能优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33360811/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com