C++ 如何为 std::string 对象预先分配内存?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3303527/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 12:35:39  来源:igfitidea点击:

how to pre-allocate memory for a std::string object?

c++string

提问by Ramadheer Singh

I need to copy a file into a string. I need someway to preallocate memory for that string object and a way to directly read the file content into that string's memory?

我需要将文件复制到字符串中。我需要某种方式为该字符串对象预先分配内存,以及一种将文件内容直接读入该字符串内存的方法吗?

回答by kennytm

std::stringhas a .reservemethodfor pre-allocation.

std::string有一个.reserve预分配方法

std::string s;
s.reserve(1048576); // reserve 1 MB
read_file_into(s);

回答by Jerry Coffin

This isn't so much an answer in itself, as a kind of a comment on/summary/comparison of a couple of other answers (as well as a quick demonstration of why I've recommended the style of code @Johannes - litb gives in his answer). Since @sbi posted an alternative that looked pretty good, and (especially) avoided the extra copy involved in reading into a stringstream, then using the .str()member to get a string, I decided to write up a quick comparison of the two:

这本身并不是一个答案,而是对其他几个答案的评论/总结/比较(以及我为什么推荐代码风格的快速演示@Johannes - litb 给出在他的回答中)。由于@sbi 发布了一个看起来不错的替代方案,并且(特别是)避免了读取.str()字符串流所涉及的额外副本,然后使用该成员获取字符串,因此我决定对两者进行快速比较:

[ Edit: I've added a third test case using @Tyler McHenry's istreambuf_iterator-based code, and added a line to print out the length of each string that was read to ensure that the optimizer didn't optimize away the reading because the result was never used.]

[ 编辑:我使用@Tyler McHenry 的istreambuf_iterator基于代码添加了第三个测试用例,并添加了一行来打印读取的每个字符串的长度,以确保优化器不会优化读取,因为结果是没用过。]

[ Edit2: And now, code from Martin York has been added as well...]

[ Edit2: 现在,还添加了来自 Martin York 的代码......]

#include <fstream>
#include <sstream>
#include <string>
#include <iostream>
#include <iterator>
#include <time.h>

int main() {
    std::ostringstream os;
    std::ifstream file("equivs2.txt");

    clock_t start1 = clock();
    os << file.rdbuf();
    std::string s = os.str();
    clock_t stop1 = clock();

    std::cout << "\ns.length() = " << s.length();

    std::string s2;

    clock_t start2 = clock();
    file.seekg( 0, std::ios_base::end );
    const std::streampos pos = file.tellg();
    file.seekg(0, std::ios_base::beg);

    if( pos!=std::streampos(-1) )
        s2.reserve(static_cast<std::string::size_type>(pos));
    s2.assign(std::istream_iterator<char>(file), std::istream_iterator<char>());
    clock_t stop2 = clock();

    std::cout << "\ns2.length = " << s2.length();

    file.clear();

    std::string s3;

    clock_t start3 = clock();   
    file.seekg(0, std::ios::end);   
    s3.reserve(file.tellg());
    file.seekg(0, std::ios::beg);

    s3.assign((std::istreambuf_iterator<char>(file)),
            std::istreambuf_iterator<char>());
    clock_t stop3 = clock();

    std::cout << "\ns3.length = " << s3.length();

    // New Test
    std::string s4;

    clock_t start4 = clock();
    file.seekg(0, std::ios::end);
    s4.resize(file.tellg());
    file.seekg(0, std::ios::beg);

    file.read(&s4[0], s4.length());
    clock_t stop4 = clock();

    std::cout << "\ns4.length = " << s3.length();

    std::cout << "\nTime using rdbuf: " << stop1 - start1;
    std::cout << "\nTime using istream_iterator: " << stop2- start2;
    std::cout << "\nTime using istreambuf_iterator: " << stop3 - start3;
    std::cout << "\nTime using read: " << stop4 - start4;
    return 0;
}

Now the impressive part -- the results. First with VC++ (in case somebody cares, Martin's code is fast enough I increased the file size to get a meaningful time for it):

现在是令人印象深刻的部分——结果。首先是 VC++(如果有人关心,Martin 的代码足够快,我增加了文件大小以获得有意义的时间):

s.length() = 7669436
s2.length = 6390688
s3.length = 7669436
s4.length = 7669436
Time using rdbuf: 184
Time using istream_iterator: 1332
Time using istreambuf_iterator: 249
Time using read: 48

s.length() = 7669436
s2.length = 6390688
s3.length = 7669436
s4.length = 7669436
使用 rdbuf 的
时间:184使用 istream_iterator 的
时间:1332使用 istreambuf_iterator 的
时间:249使用的时间

Then with gcc (cygwin):

然后使用 gcc (cygwin):

s.length() = 8278035
s2.length = 6390689
s3.length = 8278035
s4.length = 8278035
Time using rdbuf: 62
Time using istream_iterator: 2199
Time using istreambuf_iterator: 156
Time using read: 16

s.length() = 8278035
s2.length = 6390689
s3.length = 8278035
s4.length = 8278035
使用 rdbuf 的
时间:62使用 istream_iterator 的
时间:2199使用 istreambuf_iterator 的
时间:156使用的时间

[ end of edit -- the conclusions remain, though the winner has changed -- Martin's code is clearlythe fastest. ]

[编辑结束——结论仍然存在,虽然赢家已经改变——马丁的代码显然是最快的。]

The results are quite consistent with respect to which is fastest and slowest. The only inconsistency is with how muchfaster or slower one is than another. Though the placements are the same, the speed differences are muchlarger with gcc than with VC++.

关于哪个最快和最慢,结果非常一致。唯一的不一致是一个比另一个快多少或慢多少。虽然展示位置是相同的,该速度差异是用gcc比用VC大。

回答by Johannes Schaub - litb

This should be all you need:

这应该是你所需要的:

ostringstream os;
ifstream file("name.txt");
os << file.rdbuf();

string s = os.str();

This reads characters from fileand inserts them into the stringstream. Afterwards it gets the string created behind the scenes. Notice that i fell into the following trap: Using the extraction operator will skip initial whitespace. You have to use the insertion operator like above, or use the noskipwsmanipulator:

这将从中读取字符file并将它们插入到字符串流中。之后它会获取在幕后创建的字符串。请注意,我陷入了以下陷阱:使用提取运算符将跳过初始空格。你必须像上面那样使用插入运算符,或者使用noskipws操纵器:

// Beware, skips initial whitespace!
file >> os.rdbuf();

// This does not skip it
file >> noskipws >> os.rdbuf(); 

These functions are described as reading the stream character by character though (not sure what optimizations are possible here, though), i haven't timed these to determine their speed.

这些函数被描述为逐个字符地读取流(虽然不确定这里可以进行哪些优化),但我没有对它们进行计时以确定它们的速度。

回答by sbi

Just for fun, here's another way to do this:

只是为了好玩,这是另一种方法:

// Beware, brain-compiled code ahead!

std::ifstream ifs( /* ... */ );
if( !ifs.good() ) return; // whatever

std::string str;

ifs.seekg( 0, std::ios_base::end );
const std::streampos pos = ifs.tellg();
ifs.seekg( 0, std::ios_base::beg );
if( pos!=std::streampos(-1) ) // can get stream size? 
  str.reserve(static_cast<std::string::size_type>(pos));

str.assign( std::istream_iterator<char>(ifs)
          , std::istream_iterator<char>() );

I hope I didn't blow it too badly.

我希望我没有把它吹得太厉害。

回答by DevinEllingson

It seems that you are asking how to do a CString::GetBuffer, ReleaseBuffer type operation with std::string.

您似乎在问如何使用 std::string 执行 CString::GetBuffer、ReleaseBuffer 类型的操作。

I don't know of any way to do this directly, an easy way would be to just create a raw C style buffer, read into the buffer, then copy the buffer to a std::string using assign or whatever. Of course you would have to worry about buffer overrun issues etc., also I would use a std::autoptr to manage the raw buffer pointer, to enusre deallocation on exception etc. This is a bit simpler than using stringstream etc. I can provide an example if needed.

我不知道有什么方法可以直接做到这一点,一个简单的方法是创建一个原始的 C 样式缓冲区,读入缓冲区,然后使用assign 或其他方法将缓冲区复制到 std::string。当然,您将不得不担心缓冲区溢出问题等,我也会使用 std::autoptr 来管理原始缓冲区指针,以在异常等情况下重新分配。这比使用 stringstream 等要简单一些。我可以提供如果需要,请举一个例子。

Devin Ellingson

德文·艾林森

回答by Fran?ois Kupo

std::string::resize()actually allocates the required space.

std::string::resize()实际上分配了所需的空间。

std::string::reserve()may not (it's a request).

std::string::reserve()可能不会(这是一个请求)。