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

时间:2010-07-21 20:28:21

标签: c++ string

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

7 个答案:

答案 0 :(得分:27)

std::string has a .reserve method进行预分配。

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

答案 1 :(得分:14)

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

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

[编辑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;
}

现在令人印象深刻的部分 - 结果。首先使用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 ++。

答案 2 :(得分:6)

这应该是你所需要的:

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

string s = os.str();

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

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

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

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

答案 3 :(得分: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>() );

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

答案 4 :(得分:2)

答案 5 :(得分:1)

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

我不知道有什么办法直接这样做,一个简单的方法是创建一个原始C样式缓冲区,读入缓冲区,然后使用assign或其他任何东西将缓冲区复制到std :: string。当然你不得不担心缓冲区溢出问题等,我也会使用std :: autoptr来管理原始缓冲区指针,以便在异常等时进行enusre deallocation。这比使用stringstream等更简单。我可以提供如果需要的话。

Devin Ellingson

答案 6 :(得分:0)

const dataSource = [ { key: '1', name: 'Mike', }, { key: '2', name: 'John', }, ]; const columns = [ { dataIndex: 'name', key: 'name', } ]; <Table dataSource={dataSource} columns={columns} />; 实际上分配了所需的空间。

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

相关问题