如何在没有复制的情况下将std :: string的一部分变成streambuf?

时间:2014-11-28 20:16:48

标签: c++ boost boost-asio stdstring streambuf

我最近使用了boost asio,我发现我正在使用std::stringasio::streambuf s。我发现作为解析网络数据的一部分,我试图在streambufstring之间来回传递数据。一般来说,我不想乱用'格式化的io',所以iostream s不是很有用。我发现虽然ostream::operator<<()尽管有官方文档,但似乎将我的string转发到streambuf s unmlested,istream::operator>>()修改了我streambuf的内容1}} s(正如你所期望的那样'格式')。

在我看来,标准库似乎缺少大量的迭代器和流对象来处理streambufstring以及未格式化的io。例如,如果我想将string的子字符串转换为streambuf,如何在不创建string副本的情况下执行此操作?基本的全能转移可以完成如下:

// 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;    
}

打印:

message=abcdefghijk lmnopqrs tuvwxyz
sbuf_it_wholestr=abcdefghijk lmnopqrs tuvwxyz

如果我想将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;    
}    

似乎没有任何方法直接使用string::iteratorstring的一部分转储到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
}    

如果我不介意格式化的io,我可以随时从string中取出streambuf部分,但我这样做 - 格式化的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;    
}

打印:

message=abcdefghijk lmnopqrs tuvwxyz
part1=abcdefghijk
part2=lmnopqrs

如果我对丑陋的副本感到满意,我可以生成子字符串,当然 - 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;    
}

打印:

message=abcdefghijk lmnopqrs tuvwxyz
part_message=abcdefg
sbuf_it_wholestr=abcdefg

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;
}

打印:     message = abcdefghijk lmnopqrs tuvwxyz     1234 5678

line1=abcdefghijk lmnopqrs tuvwxyz
line2=1234 5678

我觉得我错过了一些Rosetta Stone,如果我发现它,处理std::stringasio::streambuf会更容易。应该放弃std::streambuf界面并使用asio::mutable_buffer,我可以从asio::streambuf::prepare()中获取?

1 个答案:

答案 0 :(得分:2)

  1.   

    istream :: operator&gt;&gt;()破坏了我的streambufs的内容(正如你所期望的那样'格式')。

    使用std::ios::binary标记打开输入流,并使用is >> std::noskipws

  2. 进行操作
  3.   

    例如,如果我想将字符串的子字符串转换为streambuf,如何在不创建字符串副本的情况下执行此操作?可以像

    一样完成基本的全进程传输

    尝试

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

    或使用boost::string_ref

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

  4.   

    似乎没有任何方法直接使用string :: iterators将部分字符串转储为streambuf:

     std::copy(it1, it2, ostreambuf_iterator<char>(os));
    
  5. 重新。解析消息行:

    您可以使用iter_split拆分为迭代器范围。

    您可以使用boost::spirit::istream_iterator

  6. 动态解析嵌入式语法