C++ 与以空结尾的字符串相比,std::string的效率有多高?

C++ 与以空结尾的字符串相比,std::string的效率有多高?,c++,stl,performance,C++,Stl,Performance,我发现std::strings与老式的以空结尾的字符串相比速度非常慢,速度非常慢,以至于它们显著地将我的整个程序的速度降低了2倍 我以为STL会慢一点,但我没意识到它会慢这么多 我使用的是VisualStudio2008,发布模式。它显示字符串的赋值比char*赋值慢100-1000倍(测试char*赋值的运行时非常困难)。我知道这不是一个公平的比较,指针赋值和字符串复制,但我的程序有很多字符串赋值,我不确定我能在所有地方使用“const reference”技巧。有了引用计数实现,我的程序就可

我发现
std::string
s与老式的以空结尾的字符串相比速度非常慢,速度非常慢,以至于它们显著地将我的整个程序的速度降低了2倍

我以为STL会慢一点,但我没意识到它会慢这么多

我使用的是VisualStudio2008,发布模式。它显示字符串的赋值比
char*
赋值慢100-1000倍(测试
char*
赋值的运行时非常困难)。我知道这不是一个公平的比较,指针赋值和字符串复制,但我的程序有很多字符串赋值,我不确定我能在所有地方使用“const reference”技巧。有了引用计数实现,我的程序就可以了,但这些实现似乎已经不存在了

我真正的问题是:为什么人们不再使用引用计数实现,这是否意味着我们都需要更加小心地避免std::string的常见性能陷阱

我的完整代码如下

#include <string>
#include <iostream>
#include <time.h>

using std::cout;

void stop()
{
}

int main(int argc, char* argv[])
{
    #define LIMIT 100000000
    clock_t start;
    std::string foo1 = "Hello there buddy";
    std::string foo2 = "Hello there buddy, yeah you too";
    std::string f;
    start = clock();
    for (int i=0; i < LIMIT; i++) {
        stop();
        f = foo1;
        foo1 = foo2;
        foo2 = f;
    }
    double stl = double(clock() - start) / CLOCKS\_PER\_SEC;

    start = clock();
    for (int i=0; i < LIMIT; i++) {
        stop();
    }
    double emptyLoop = double(clock() - start) / CLOCKS_PER_SEC;

    char* goo1 = "Hello there buddy";
    char* goo2 = "Hello there buddy, yeah you too";
    char *g;
    start = clock();
    for (int i=0; i < LIMIT; i++) {
        stop();
        g = goo1;
        goo1 = goo2;
        goo2 = g;
    }
    double charLoop = double(clock() - start) / CLOCKS_PER_SEC;
    cout << "Empty loop = " << emptyLoop << "\n";
    cout << "char* loop = " << charLoop << "\n";
    cout << "std::string = " << stl << "\n";
    cout << "slowdown = " << (stl - emptyLoop) / (charLoop - emptyLoop) << "\n";
    std::string wait;
    std::cin >> wait;
    return 0;
}
#包括
#包括
#包括
使用std::cout;
无效停止()
{
}
int main(int argc,char*argv[])
{
#定义限额100000000
时钟没有启动;
std::string foo1=“你好,伙计”;
std::string foo2=“你好,伙计,是的,你也是”;
std::字符串f;
开始=时钟();
对于(int i=0;i你肯定是做错了什么,或者至少没有“公平地”比较STL和你自己的代码。当然,如果没有代码来查看,很难更具体


这可能是因为您使用STL构建代码的方式会导致更多构造函数运行,或者没有以与您自己实现操作时所做操作相匹配的方式重新使用分配的对象,等等。

它们没有出错。STL实现通常比您的实现更好


我相信,对于一个非常特殊的情况,您可以编写更好的代码,但是因子2太多了……您一定是做错了什么。

如果使用正确,std::string与char*一样高效,但有额外的保护

如果您遇到STL的性能问题,很可能是您做错了什么

此外,STL实现在编译器中不是标准的。我知道SGI的STL和STLPort通常表现良好


这是我完全认真的,你可以是一个C++天才,并且设计出比STL更复杂的代码。它不太可能,但是谁知道,你可以是C++的勒布朗·詹姆斯。

< p>如果你有一个向量的最终大小的指示,你可以通过调用Stand()来防止过大的调整大小。在填充之前。

很大一部分原因可能是在STL的现代实现中不再使用引用计数

故事是这样的(如果我错了,有人纠正我):一开始,STL实现使用引用计数,速度很快,但不是线程安全的-实现者希望应用程序程序员在更高级别插入自己的锁定机制,以使其线程安全,因为如果在两个级别执行锁定,那么这将使速度降低两倍

然而,世界上的程序员太无知或懒惰,以至于无法在任何地方插入锁。例如,如果多线程程序中的工作线程需要读取std::string命令行参数,那么即使只是读取字符串也需要锁,否则可能会导致崩溃。(2个线程在不同的CPU(+1)上同时递增引用计数,但分别递减(-2),因此引用计数下降到零,内存被释放。)

因此,实现者放弃了引用计数,而是让每个std::string始终拥有自己的字符串副本

所以现在,即使将一个std::string简单地分配给另一个std::string(或者等效地,将一个std::string作为参数传递给一个函数),也需要大约400条机器代码指令,而不是分配一个char*所需的2条指令,这会降低200倍

我在一个主要程序上测试了std::string的低效程度,与以空结尾的字符串相比,它的总体速度降低了约100%。我还使用以下代码测试了原始std::string分配,该代码表示std::string分配的速度降低了100-900倍。(我无法测量char*赋值的速度)。我还调试了std::string operator=()函数-我在堆栈中的深度达到膝盖,大约有7层,然后点击了“memcpy()”

我不确定有没有解决办法。也许如果你需要你的程序快,使用普通的老C++,如果你更关心自己的生产力,你应该使用java。
#define LIMIT 800000000
clock_t start;
std::string foo1 = "Hello there buddy";
std::string foo2 = "Hello there buddy, yeah you too";
std::string f;

start = clock();
for (int i=0; i < LIMIT; i++) {
    stop();
    f    = foo1;
    foo1 = foo2;
    foo2 = f;
}
double stl = double(clock() - start) / CLOCKS_PER_SEC;

start = clock();
for (int i=0; i < LIMIT; i++) {
    stop();
}
double emptyLoop = double(clock() - start) / CLOCKS_PER_SEC;

char* goo1 = "Hello there buddy";
char* goo2 = "Hello there buddy, yeah you too";
char *g;

start = clock();
for (int i=0; i < LIMIT; i++) {
    stop();
    g = goo1;
    goo1 = goo2;
    goo2 = g;
}
double charLoop = double(clock() - start) / CLOCKS_PER_SEC;

TfcMessage("done", 'i', "Empty loop = %1.3f s\n"
                        "char* loop = %1.3f s\n"
                        "std::string loop = %1.3f s\n\n"
                        "slowdown = %f", 
                        emptyLoop, charLoop, stl, 
                        (stl - emptyLoop) / (charLoop - emptyLoop));
#定义限制80000000
时钟没有启动;
std::string foo1=“你好,伙计”;
std::string foo2=“你好,伙计,是的,你也是”;
std::字符串f;
开始=时钟();
对于(int i=0;i// you do it wrong
void setMember(string a) {
    this->a = a; // better: swap(this->a, a);
}
// let's add a Foo into the vector
v.push_back(Foo(a, b));
string a = b + c + e;
v.emplace_back(a, b);
std::string a = "String a"
std::string b = "String b"

// Use
a.swap(b);

// Instead of
std::string tmp = a;
a = b;
b = tmp;
std::string a = "this is a";
std::string b = "this is b"
a = b;
char* loop = 19.921
string = 0.375
slowdown = 0.0188244
#include <string>
#include <iostream>
#include <ctime>

using namespace std;

#define LIMIT 100000000

char* make_string(const char* src)
{
    return strcpy((char*)malloc(strlen(src)+1), src);
}

int main(int argc, char* argv[])
{
    clock_t start;
    string foo1 = "Hello there buddy";
    string foo2 = "Hello there buddy, yeah you too";
    start = clock();
    for (int i=0; i < LIMIT; i++)
        foo1.swap(foo2);
    double stl = double(clock() - start) / CLOCKS_PER_SEC;

    char* goo1 = make_string("Hello there buddy");
    char* goo2 = make_string("Hello there buddy, yeah you too");
    char *g;
    start = clock();
    for (int i=0; i < LIMIT; i++) {
        g = make_string(goo1);
        free(goo1);
        goo1 = make_string(goo2);
        free(goo2);
        goo2 = g;
    }
    double charLoop = double(clock() - start) / CLOCKS_PER_SEC;
    cout << "char* loop = " << charLoop << "\n";
    cout << "string = " << stl << "\n";
    cout << "slowdown = " << stl / charLoop << "\n";
    string wait;
    cin >> wait;
}
shared_ptr<string> ref_counted = make_shared<string>("test");
shared_ptr<string> shallow_copy = ref_counted; // no deep copies, just 
                                               // increase ref count
string const string& char* Java string --------------------------------------------------------------------------------------------------- Efficient no ** yes yes yes assignment Thread-safe yes yes yes yes memory management yes no no yes done for you