为什么std :: vector <char>比std :: string更快?

use*_*511 -1 c++ string stl vector c++11

我写了一个小测试,我试图比较调整容器大小的运行速度,然后用std::generate_n它来填充它.我正在比较std::stringstd::vector<char>.这是程序:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <random>
#include <vector>

int main()
{
    std::random_device rd;
    std::default_random_engine rde(rd());
    std::uniform_int_distribution<int> uid(0, 25);

    #define N 100000

#ifdef STRING
    std::cout << "String.\n";
    std::string s;
    s.resize(N);
    std::generate_n(s.begin(), N, 
                    [&]() { return (char)(uid(rde) + 65); });
#endif

#ifdef VECTOR
    std::cout << "Vector.\n";
    std::vector<char> v;
    v.resize(N);
    std::generate_n(v.begin(), N, 
                    [&]() { return (char)(uid(rde) + 65); });
#endif

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我的Makefile:

test_string:
    g++ -std=c++11 -O3 -Wall -Wextra -pedantic -pthread -o test test.cpp -DSTRING
    valgrind --tool=callgrind --log-file="test_output" ./test
    cat test_output | grep "refs"

test_vector:
    g++ -std=c++11 -O3 -Wall -Wextra -pedantic -pthread -o test test.cpp -DVECTOR
    valgrind --tool=callgrind --log-file="test_output" ./test
    cat test_output | grep "refs"
Run Code Online (Sandbox Code Playgroud)

以及对某些值的比较N:

N=10000
String: 1,865,367
Vector: 1,860,906

N=100000
String: 5,295,213
Vector: 5,290,757

N=1000000
String: 39,593,564
Vector: 39,589,108
Run Code Online (Sandbox Code Playgroud)

std::vector<char>每次都出现在前面.由于它似乎更高效,甚至可以使用std::string什么?

arh*_*aco 5

我用过#define N 100000000.每个场景测试3次,在所有场景中字符串更快.不使用Valgrind,它没有意义.

OS: Ubuntu 14.04. Arch:x86_64 CPU: Intel(R) Core(TM) i5-4670 CPU @ 3.40GHz.

$COMPILER -std=c++11 -O3 -Wall -Wextra -pedantic -pthread -o test x.cc -DVECTOR    
$COMPILER -std=c++11 -O3 -Wall -Wextra -pedantic -pthread -o test x.cc -DSTRING
Run Code Online (Sandbox Code Playgroud)

时报:

compiler/variant           | time(1) | time(2) | time(3)
---------------------------+---------+---------+--------
g++ 4.8.2/vector    Times: | 1.724s  | 1.704s  | 1.669s
g++ 4.8.2/string    Times: | 1.675s  | 1.678s  | 1.674s
clang++ 3.5/vector  Times: | 1.929s  | 1.934s  | 1.905s
clang++ 3.5/string  Times: | 1.616s  | 1.612s  | 1.619s
Run Code Online (Sandbox Code Playgroud)

  • 这是一个答案.问题是"为什么矢量更快",这个答案表明矢量不是更快(至少普遍).关于asnwer中valgrind的问题应该是一个评论. (8认同)
  • 这充其量只是一个评论。 (2认同)

Chr*_*ckl 5

std::vector 每次都领先。既然它看起来性能更高,那么使用 std::string 还有什么意义呢?

即使我们假设您的观察结果适用于各种不同的系统和不同的应用程序上下文,但std::string出于各种原因使用它仍然有意义,这些原因都源于字符串与向量具有不同语义的事实。字符串是一段文本(至少是简单的、非国际化的英文文本),向量是字符的集合。

我想到两件事:

  • 使用方便。std::string可以从字符串文字构造,有很多方便的运算符,并且可以遵循特定于字符串的算法。尝试std::string x = "foo" + ("bar" + boost::algorithm::replace_all_copy(f(), "abc", "ABC").substr(0, 10)std::vector<char>...

  • std::string在 MSVC 中通过小字符串优化 (SSO) 实现,在许多情况下完全消除堆分配。SSO 基于字符串通常非常短的观察,这对于向量来说当然不能这样说。

请尝试以下操作:

#include <iostream>
#include <vector>
#include <string>

int main()
{
    char const array[] = "short string";

#ifdef STRING
    std::cout << "String.\n";
    for (int i = 0; i < 10000000; ++i) {
        std::string s = array;
    }
#endif

#ifdef VECTOR
    std::cout << "Vector.\n";
    for (int i = 0; i < 10000000; ++i) {
        std::vector<char> v(std::begin(array), std::end(array));
    }
#endif
}
Run Code Online (Sandbox Code Playgroud)

std::string版本应该优于该std::vector版本,至少对于 MSVC 来说是这样。在我的机器上差异大约是 2-3 秒。对于较长的字符串,结果应该不同。

当然,这也不能证明什么,除了两件事:

  • 性能测试很大程度上取决于环境。
  • 性能测试应该测试在真实程序中实际执行的操作。对于字符串,您的程序可能会处理许多小字符串而不是单个大字符串,因此请测试小字符串。