C++ 如何在不复制的情况下将std::string的一部分放入streambuf?

C++ 如何在不复制的情况下将std::string的一部分放入streambuf?,c++,boost,boost-asio,stdstring,streambuf,C++,Boost,Boost Asio,Stdstring,Streambuf,我最近经常使用boost-asio,我发现我经常使用std::strings和asio::streambufs。我发现,作为解析网络数据的一部分,我试图在streambufs和strings之间来回获取数据。一般来说,我不想乱搞“格式化io”,所以iostreams不是很有用。我发现,ostream::operator()会损坏我的streambufs的内容(因为它是“格式化的”),这是您所期望的 在我看来,标准库确实缺少了大量迭代器和流对象来处理streambufs和strings以及未格式化

我最近经常使用boost-asio,我发现我经常使用
std::string
s和
asio::streambuf
s。我发现,作为解析网络数据的一部分,我试图在
streambuf
s和
string
s之间来回获取数据。一般来说,我不想乱搞“格式化io”,所以
iostream
s不是很有用。我发现,
ostream::operator()
会损坏我的
streambuf
s的内容(因为它是“格式化的”),这是您所期望的

在我看来,标准库确实缺少了大量迭代器和流对象来处理
streambuf
s和
string
s以及未格式化io。例如,如果我想将
字符串的子字符串
放入
streambuf
,如何在不创建
字符串
副本的情况下执行此操作?基本的全进全出传输可通过以下方式完成:

// 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;    
}
如果我只想将
streambuf
的一部分转换成字符串,这似乎非常困难,因为
istreambuf\u迭代器
不是随机访问迭代器,也不支持算术:

// 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;    
}    
如果我不介意格式化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;    
}
如果我对难看的副本没意见,我可以生成一个子字符串,当然-
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;    
}
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;
}
我觉得我错过了一些罗塞塔石,如果我发现了它,处理
std::string
asio::streambuf
会容易得多。a是否应该放弃
std::streambuf
接口,使用
asio::mutable_buffer
,我可以从
asio::streambuf::prepare()
中得到它

  • istream::operator>>()会破坏我的streambufs的内容(正如您所期望的,因为它是“格式化的”)

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

  • 例如,如果我想将字符串的子字符串获取到streambuf中,如何在不创建字符串副本的情况下执行该操作?基本的全进全出传输可以像

    试着

     outstream.write(s.begin()+start, length);
    
    或者使用
    boost::string\u ref

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

    说得太长了。我认为stringstreams不支持移动。我想我已经看到了一个增加这一点的提议。同时,字符串流并不是非常复杂,所以你可以自己写。我在回答中给出了一些提示,但实际上,在将来尝试针对一个特定的问题(当然,在搜索现有答案之后)。这个答案是如此的分歧,我认为一个带有“快速指针”的答案是我们所能做的。你是说ifstream吗?如何使用ios::binary打开通用istream?另外,std::noskipws在这里也没有帮助——它只是告诉istream不要跳过前导空格。istream仍将根据空格标记输入。@TEDMidleton
    istream\u迭代器
    ,例如,将返回所有字符,以及包含在
    noskipws
    中的空格。我说的是任何具体的
    istream&
    实例,是的,我显然遗漏了一些东西。如何使用ios::binary打开通用istream?你能发布实际代码吗?istream没有支持此功能的ctor,而且我找不到任何可以将istream注释为“ios::binary”的访问器。因此,我谈论的是具体的
    istream&
    实例,而不是
    istream
    实例。我还确认了“是”,以回答“您在谈论ifstream吗”(尽管范围比文件更广)。我已经尝试从我的答案措辞中消除混淆。std::copy(it1,it2,ostreambuf_迭代器(os));这正是我想要的。谢谢
    message=abcdefghijk lmnopqrs tuvwxyz
    part_message=abcdefg
    sbuf_it_wholestr=abcdefg
    
    // 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;
    }
    
    line1=abcdefghijk lmnopqrs tuvwxyz
    line2=1234 5678
    
     outstream.write(s.begin()+start, length);
    
     outstream << boost::string_ref(s).instr(start, length);
    
     std::copy(it1, it2, ostreambuf_iterator<char>(os));