简体   繁体   English

如何在不复制的情况下将std :: string的一部分放入流缓冲中?

[英]How to get part of a std::string into a streambuf without copying?

I'm using boost asio a lot lately and I find that I'm working with std::string s and asio::streambuf s quite a bit. 我最近经常使用boost asio,发现使用了std::stringasio::streambuf相当多。 I find that I'm trying to get data back and forth between streambuf s and string sa lot as part of parsing network data. 我发现我正在尝试在streambufstring之间来回获取数据,这是解析网络数据的一部分。 In general, I don't want to mess around with 'formatted io', so iostream s aren't very useful. 通常,我不想弄乱“ formatted io”,所以iostream并不是很有用。 I've found that while ostream::operator<<() , in spite of the official documentation, seems to relay my string s into streambuf s unmolested, istream::operator>>() mangles the contents of my streambuf s (as you would expect given that it's 'formatted'). 我发现,尽管有官方文档, ostream::operator<<()似乎streambuf我的string中继到streambuf ,但istream::operator>>()破坏了我的streambuf的内容(如您会期望它是“格式化的”)。

It really seems to me like the standard library is missing a whole lot of iterators and stream objects for dealing with streambuf s and string s and unformatted io. 在我看来,标准库确实缺少用于处理streambufstring以及未格式化io的大量迭代器和流对象。 For example, if I want to get a substring of a string into a streambuf , how do I do that without creating a copy of the string ? 例如,如果要将字符串的子string放入streambuf ,如何在不创建string副本的情况下做到这一点? A basic all-in-all-out transfer can be accomplished like: 基本的全进全出传输可以像这样完成:

// Get a whole string into a streambuf, and then get the whole streambuf back
//  into another string
{
    boost::asio::streambuf sbuf;
    iostream os(&sbuf);
    string message("abcdefghijk lmnopqrs tuvwxyz");
    cout << "message=" << message << endl;
    os << message;
    std::istreambuf_iterator<char> sbit(&sbuf);
    std::istreambuf_iterator<char> end;
    std::string sbuf_it_wholestr(sbit, end);
    cout << "sbuf_it_wholestr=" << sbuf_it_wholestr << endl;    
}

prints: 打印:

message=abcdefghijk lmnopqrs tuvwxyz
sbuf_it_wholestr=abcdefghijk lmnopqrs tuvwxyz

If I want to get just part of a streambuf into a string, that seems really hard, because istreambuf_iterator isn't a random access iterator and doesn't support arithmetic: 如果我只想将streambuf一部分放入字符串中,那看起来确实很难,因为istreambuf_iterator不是随机访问迭代器,也不支持算术运算:

// Get a whole string into a streambuf, and then get part of the streambuf back
//  into another string. We can't do this because istreambuf_iterator isn't a
//  random access iterator!
{
    boost::asio::streambuf sbuf;
    iostream os(&sbuf);
    string message("abcdefghijk lmnopqrs tuvwxyz");
    cout << "message=" << message << endl;
    os << message;
    std::istreambuf_iterator<char> sbit(&sbuf);
    // This doesn't work
    //std::istreambuf_iterator<char> end = sbit + 7; // Not random access!
    //std::string sbuf_it_partstr(sbit, end);
    //cout << "sbuf_it_partstr=" << sbuf_it_partstr << endl;    
}    

And there doesn't seem to be any way of directly using string::iterator s to dump part of a string into a streambuf : 而且似乎没有任何直接使用string::iterator的方法将一部分string转储到streambuf

// istreambuf_iterator doesn't work in std::copy either
{
    boost::asio::streambuf sbuf;
    iostream os(&sbuf);
    string message("abcdefghijk lmnopqrs tuvwxyz");
    cout << "message=" << message << endl;
    std::istreambuf_iterator<char> sbit(&sbuf);
    //std::copy(message.begin(), message.begin()+7, sbit); // Doesn't work here
}    

I can always pull partial string s out of a streambuf if I don't mind formatted io, but I do - formatted io is almost never what I want: 如果我不介意格式化io,我总是可以从streambuf拉出部分string s,但是我愿意-格式化io几乎从来不是我想要的:

// Get a whole string into a streambuf, and then pull it out using an ostream
// using formatted output
{
    boost::asio::streambuf sbuf;
    iostream os(&sbuf);
    string message("abcdefghijk lmnopqrs tuvwxyz");
    cout << "message=" << message << endl;
    string part1, part2;
    os << message;
    os >> part1;
    os >> part2;
    cout << "part1=" << part1 << endl;    
    cout << "part2=" << part2 << endl;    
}

prints: 打印:

message=abcdefghijk lmnopqrs tuvwxyz
part1=abcdefghijk
part2=lmnopqrs

If I'm ok with an ugly copy, I can generate a substring, of course - std::string::iterator is random access... 如果我可以接受一个丑陋的副本,那么我可以生成一个子字符串,当然std::string::iterator 随机访问的...

// Get a partial string into a streambuf, and then pull it out using an
//  istreambuf_iterator
{
    boost::asio::streambuf sbuf;
    iostream os(&sbuf);
    string message("abcdefghijk lmnopqrs tuvwxyz");
    cout << "message=" << message << endl;
    string part_message(message.begin(), message.begin()+7);
    os << part_message;
    cout << "part_message=" << part_message << endl;
    std::istreambuf_iterator<char> sbit(&sbuf);
    std::istreambuf_iterator<char> end;
    std::string sbuf_it_wholestr(sbit, end);
    cout << "sbuf_it_wholestr=" << sbuf_it_wholestr << endl;    
}

prints: 打印:

message=abcdefghijk lmnopqrs tuvwxyz
part_message=abcdefg
sbuf_it_wholestr=abcdefg

The stdlib also has the curiously stand-alone std::getline() , which lets you pull individual lines out of an ostream : stdlib还具有奇怪的独立std::getline() ,它使您可以将单个行从ostream拉出:

// If getting lines at a time was what I wanted, that can be accomplished too...          
{    
    boost::asio::streambuf sbuf;
    iostream os(&sbuf);
    string message("abcdefghijk lmnopqrs tuvwxyz\n1234 5678\n");
    cout << "message=" << message << endl;
    os << message;
    string line1, line2;
    std::getline(os, line1);
    std::getline(os, line2);
    cout << "line1=" << line1 << endl;
    cout << "line2=" << line2 << endl;
}

prints: message=abcdefghijk lmnopqrs tuvwxyz 1234 5678 打印:message = abcdefghijk lmnopqrs tuvwxyz 1234 5678

line1=abcdefghijk lmnopqrs tuvwxyz
line2=1234 5678

I feel like there's some Rosetta Stone that I've missed and that dealing with std::string and asio::streambuf would be so much easier if I discovered it. 我感觉好像有些罗塞塔石碑错过了,如果我发现了std::stringasio::streambuf ,处理起来会容易得多。 Should a just abandon the std::streambuf interface and make use of asio::mutable_buffer , which I can get out of asio::streambuf::prepare() ? 应该只是放弃std::streambuf接口并使用asio::mutable_buffer ,我可以退出asio::streambuf::prepare()吗?

  1. istream::operator>>() mangles the contents of my streambufs (as you would expect given that it's 'formatted'). istream :: operator >>()处理我的streambuf的内容(正如您所期望的那样,它是“格式化的”)。

    Open your input stream with std::ios::binary flag and manipulate it with is >> std::noskipws 使用std::ios::binary标志打开输入流,并使用is >> std::noskipws

  2. For example, if I want to get a substring of a string into a streambuf, how do I do that without creating a copy of the string? 例如,如果要将字符串的子字符串放入流缓冲中,如何在不创建字符串副本的情况下做到这一点? A basic all-in-all-out transfer can be accomplished like 基本的全进全出传输可以像

    Try like 尝试像

      outstream.write(s.begin()+start, length); 

    Or use boost::string_ref : 或使用boost::string_ref

      outstream << boost::string_ref(s).instr(start, length); 

  3. And there doesn't seem to be any way of directly using string::iterators to dump part of a string into a streambuf: 而且似乎没有任何直接使用string :: iterators将一部分字符串转储到streambuf中的方法:

      std::copy(it1, it2, ostreambuf_iterator<char>(os)); 
  4. Re. 回覆。 parsing the message lines: 解析消息行:

    You can split into iterator ranges with iter_split . 您可以使用iter_split拆分为迭代器范围。

    You can parse an embedded grammar on the fly with boost::spirit::istream_iterator 您可以使用boost::spirit::istream_iterator即时解析嵌入式语法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM