快速将CString移动到std :: string

时间:2015-03-10 10:45:30

标签: c++ string c++11 mfc

我在代码库中混合使用CStringconst char*std::string(非unicode),其中所有新代码都使用std::string。我现在必须做以下事情:

{
    CString tempstring;
    load_cstring_legacy_method(tempstring);
    stdstring = tempstring;
}

并担心性能。这些字符串是DNA序列,因此我们可以很容易地拥有100多个字符串~3M字符。请注意,调整load_cstring_legacy_method不是一种选择。我做了一个快速测试:

// 3M
const int stringsize = 3000000;
const int repeat     = 1000;

std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
for ( int i  = 0; i < repeat; ++i ){
    CString cstring('A', stringsize);
    std::string stdstring(cstring); // Comment out
    cstring.Empty();
}
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - startTime).count() << " ms" << std::endl;

并评论std::string给出850 ms,其分配为3600 ms。差异的程度令人惊讶,所以我猜基准测试可能没有达到我的预期。假设有一个惩罚,有没有办法可以避免它?

3 个答案:

答案 0 :(得分:1)

所以你的问题是让std :: string构造更快?

在我的机器上,比较这个

std::string stdstring(cstring); // 4741 ms

我以这种方式获得更好的表现:

std::string stdstring(cstring, stringsize); // 3419 ms

或者如果std :: string已经存在,就像问题的第一部分所示:

stdstring.assign(cstring, stringsize); // 3408 ms

答案 1 :(得分:0)

使用更有效的内存分配器。像记忆竞技场/区域这样的东西会大大有助于分配成本。

如果你真的非常绝望,理论上你可以将ReleaseBuffer与一些可怕的分配器黑客结合起来以完全避免副本。但这会带来很多痛苦。

此外,如果您遇到严重问题,可以考虑更改字符串实现。 Visual Studio附带的std::string使用SSO或小字符串优化。这听起来确实如此 - 它优化了非常小的字符串,这种字符串很常见,但不一定适合这种用例。像COW这样的另一个实现可能更合适(如果在多线程环境中这样做,请非常小心)。

最后,如果您使用的是旧版本的VS,则还应考虑升级。就性能而言,移动语义是一个巨大的应变。

答案 2 :(得分:0)

CString可能是Unicode版本,这解释了缓慢。通用转换例程无法知道所使用的字符仅限于“ACGT”。

然而,你可以无耻地利用这一点。

{
    CString tempstring;
    load_cstring_legacy_method(tempstring);
    int len = tempstring.GetLength();
    stdstring.reserve(len);
    for(int i = 0; i != len; ++i)
    {
        stdstring.push_back(static_cast<char>(tempstring[i]));
    }
}

便携式?只有CString,所以Windows变种。