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

Ram*_*ngh 23 c++ string

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

ken*_*ytm 30

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

std::string s;
s.reserve(1048576); // reserve 1 MB
read_file_into(s);
Run Code Online (Sandbox Code Playgroud)


Jer*_*fin 15

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

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

[编辑2:现在,马丁约克的代码也已添加......]

#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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

然后用gcc(cygwin):

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

[编辑结束 - 结论仍然存在,虽然获胜者已经改变 - 马丁的代码显然是最快的.]

结果非常一致,最快和最慢.唯一的矛盾是如何较慢的速度或高于另一个.虽然展示位置是相同的,该速度差异是用gcc比用VC大.


Joh*_*itb 6

这应该是你所需要的:

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

string s = os.str();
Run Code Online (Sandbox Code Playgroud)

这将读取字符file并将其插入到字符串流中.然后它获取幕后创建的字符串.请注意,我陷入了以下陷阱:使用提取运算符将跳过初始空格.您必须使用上面的插入操作符,或使用noskipws操纵器:

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

// This does not skip it
file >> noskipws >> os.rdbuf(); 
Run Code Online (Sandbox Code Playgroud)

这些函数被描述为逐个字符地读取流(尽管不知道这里可能进行哪些优化),我没有时间来确定它们的速度.

  • 这确实复制了两次,一次复制到`ostringstream`缓冲区,第二次复制到`s`。 (2认同)

sbi*_*sbi 5

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

// 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>() );
Run Code Online (Sandbox Code Playgroud)

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

  • +1,等待有人详细说明基于流迭代器的代码:) (2认同)

小智 5

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

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