字符串中最优化的连接方式

新手上路,请多包涵

我们每天都会遇到很多情况,我们必须在代码中进行繁琐且非常多的字符串操作。我们都知道字符串操作是昂贵的操作。我想知道可用版本中哪个最便宜。

最常见的操作是串联(这是我们可以在一定程度上控制的东西)。在 C++ 中连接 std::strings 的最佳方法是什么以及加速连接的各种解决方法?

我是说,

 std::string l_czTempStr;

1).l_czTempStr = "Test data1" + "Test data2" + "Test data3";

2). l_czTempStr =  "Test data1";
    l_czTempStr += "Test data2";
    l_czTempStr += "Test data3";

3). using << operator

4). using append()

另外,使用 CString 比使用 std::string 有什么好处吗?

原文由 Bhupesh Pant 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

这是一个小型测试套件:

 #include <iostream>
#include <string>
#include <chrono>
#include <sstream>

int main ()
{
    typedef std::chrono::high_resolution_clock clock;
    typedef std::chrono::duration<float, std::milli> mil;
    std::string l_czTempStr;
    std::string s1="Test data1";
    auto t0 = clock::now();
    #if VER==1
    for (int i = 0; i < 100000; ++i)
    {
        l_czTempStr = s1 + "Test data2" + "Test data3";
    }
    #elif VER==2
    for (int i = 0; i < 100000; ++i)
    {
        l_czTempStr =  "Test data1";
        l_czTempStr += "Test data2";
        l_czTempStr += "Test data3";
    }
    #elif VER==3
    for (int i = 0; i < 100000; ++i)
    {
        l_czTempStr =  "Test data1";
        l_czTempStr.append("Test data2");
        l_czTempStr.append("Test data3");
    }
    #elif VER==4
    for (int i = 0; i < 100000; ++i)
    {
        std::ostringstream oss;
        oss << "Test data1";
        oss << "Test data2";
        oss << "Test data3";
        l_czTempStr = oss.str();
    }
    #endif
    auto t1 = clock::now();
    std::cout << l_czTempStr << '\n';
    std::cout << mil(t1-t0).count() << "ms\n";
}

关于 大肠杆菌

编译如下:

clang++ -std=c++11 -O3 -DVER=1 -Wall -pedantic -pthread main.cpp

21.6463 毫秒

-DVER=2

6.61773ms

-DVER=3

6.7855ms

-DVER=4

102.015 毫秒

看起来 2)+= 是赢家。

(同时编译有无 -pthread 似乎会影响时间)

原文由 Jesse Good 发布,翻译遵循 CC BY-SA 3.0 许可协议

#include <concepts>
#include <string>

template<class T>
concept string_like_t = requires(const T & str)
{
    {std::size(str)} -> std::same_as<size_t>;
    {*std::data(str)} -> std::convertible_to<std::remove_cvref_t<decltype(str[0])>>;
};
template<string_like_t T>
using char_t = std::remove_cvref_t<decltype(std::declval<T>()[0])>;

template<class Alloc, string_like_t First, string_like_t... Rest>
    requires (!string_like_t<Alloc>)
auto concat(const Alloc& alloc, const First& first, const Rest&... rest)
{
    std::basic_string<char_t<First>, std::char_traits<char_t<First>>, Alloc> result{ alloc };
    result.reserve(std::size(first) + (std::size(rest) + ...));
    result.append(std::data(first), std::size(first));
    (result.append(std::data(rest), std::size(rest)), ...);
    return result;
}

template<string_like_t First, string_like_t... Rest>
auto concat(const First& first, const Rest&... rest)
{
    typename std::basic_string<char_t<First>>::allocator_type alloc{};
    return concat(alloc, first, rest...);
}

#include <string_view>
#include <iostream>
#include <memory_resource>
int main()
{
    std::pmr::monotonic_buffer_resource mr { 1000 };
    std::pmr::polymorphic_allocator<char> alloc {&mr};
    std::string xxx = "xxxxxx";
    std::string_view yyy = "TEST";
    std::pmr::string zzz {", zzz", &mr};
    std::cout << concat(yyy, "123: ", "test", xxx, zzz) << std::endl;
    std::cout << concat(alloc, yyy, "123: ", "test", xxx, zzz) << std::endl;

    return 0;
}

似乎是最优化的 C++20 版本。支持多态分配器

原文由 Sergey E. 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题