【问题标题】:What is the fastest way to resize std::string?调整 std::string 大小的最快方法是什么?
【发布时间】:2016-08-06 08:54:35
【问题描述】:

我正在处理一个 C++ 项目(使用 VS2008),我需要将一个非常大的 XML 文件从一个文件加载到 std::wstring。目前以下行在加载数据之前保留内存:

//std::wstring str;
//size_t ncbDataSz = file size in bytes

str.resize(ncbDataSz / sizeof(WCHAR));

但我当前的问题是resize 方法对于较大的字符串大小需要很长时间(我刚刚在x64 项目中使用12GB 的免费桌面PC 测试了它的3GB 数据RAM,大约需要 4-5 秒才能完成。)

所以我很好奇,有没有更快(更优化)的方法来调整std::string 的大小?我只要求 Windows。

【问题讨论】:

  • std::string::reserve 保留,std::string::resize 也写入内存...我想您将立即覆盖它。
  • 您要调整大小还是保留?
  • @LogicStuff:reserve 是一只奇怪的野兽。它“保留”了内存,但不能直接以连续字节数组的形式访问它,对吧?我需要打电话给append。在那种情况下,这种类型的优化对我来说毫无用处。
  • @c00000fd 不,保留的内存将是连续的,因为每个std::basic_string 都是。否则什么都行不通。 Similar Q&A about the performance differences(迭代器不是这里的问题)。
  • @LogicStuff:是的,它是连续的。但是我如何以字节数组的形式访问它?就像我在下面的评论中显示的那样,这个 str.reserve(ncbDataSz / sizeof(WCHAR)); ReadFile(hFile, &str[0], ncbDataSz, szRead, NULL); 不起作用,因为字符串内部的大小仍然为 0。

标签: c++ windows visual-studio-2008 stdstring


【解决方案1】:

您可以使用 char_traits 实例化 basic_string,这对 assign(count) 没有任何作用:

#include <string>

struct noinit_char_traits : std::char_traits<char> {
    using std::char_traits<char>::assign;
    static char_type* assign(char_type* p, std::size_t count, char_type a) { return p; }
};

using noinit_string = std::basic_string<char, noinit_char_traits>;

请注意,它也会影响 basic_string::fill() 等函数。

【讨论】:

    【解决方案2】:

    您可以使用std::string::reserve 分配它而不是调整输入字符串的大小,因为调整大小也会初始化每个元素。

    您可以尝试这样的方法,看看它是否可以提高您的性能:

    std::wstring load_file(std::string const& filename)
    {
        std::wifstream ifs(filename, std::ios::ate);
    
        // errno works on POSIX systems not sure about windows
        if(!ifs)
            throw std::runtime_error(std::strerror(errno));
    
        std::wstring s;
        s.reserve(ifs.tellg()); // allocate but don't initialize
        ifs.seekg(0);
    
        wchar_t buf[4096];
        while(ifs.read(buf, sizeof(buf)/sizeof(buf[0])))
            s.append(buf, buf + ifs.gcount()); // this will never reallocate
    
        return s;
    }
    

    【讨论】:

    • 谢谢。但是你正在做的是你预先分配了两个缓冲区:s.reservewchar_t buf,我试图只用一个。那么在我做s.reserve 之后如何直接加载到它?或者ReadFile(hFile, &amp;s[0], sz, szRead, NULL);我需要调整它的大小,对。但是怎么做呢?
    • @c00000fd 您无法读取保留的内存。但是,buf[4096] 的分配在堆栈上,速度很快(一条指令?)。归根结底,只有测量才能告诉您它是否更快。
    • 我说的是 GB 的数据,所以堆栈是不可能的。从文件中以小块的形式加载它比我不使用resize的收益还要慢。
    • @c00000fd 如果您查看我的示例,堆栈仅用于文件读取缓冲区。不是整个文件。文件读取已经被缓冲,读取任务将取决于 HDD 驱动器的速度,而不是其他任何事情。但我建议你测量一下,看看有没有改善。
    • 是的,我看到了你的例子......这是一本教科书std::string 的东西。你没有按照我说的去做。但这没关系。我似乎找不到比使用std::string 模板调用resize 更优化的东西了。否则,如果我使用reserve,它会分配缓冲区,这很好,但随后我会失去在调用reserve 时使用reserve 获得的“任何节省”。
    猜你喜欢
    • 2010-10-24
    • 2021-11-06
    • 1970-01-01
    • 1970-01-01
    • 2012-01-01
    • 1970-01-01
    • 2016-11-19
    • 2014-09-10
    • 2015-02-07
    相关资源
    最近更新 更多