Domanda

A quanto pare boost::asio::async_read non piace stringhe, come l'unico di sovraccarico di boost::asio::buffer mi permette di creare const_buffers, così mi sono bloccato con la lettura di tutto in una streambuf.
Ora voglio copiare il contenuto della streambuf in una stringa, ma supporta apparentemente solo scrivendo a char * (sgetn()), la creazione di un istream con lo streambuf e utilizzando getline().

C'è un altro modo per creare una stringa con i contenuti streambuf senza copiare eccessiva?

È stato utile?

Soluzione

Non so se si conta come " copia eccessiva ", ma è possibile utilizzare uno stringstream:

std::ostringstream ss;
ss << someStreamBuf;
std::string s = ss.str();

Come, di leggere tutto da stdin in una stringa, fare

std::ostringstream ss;
ss << std::cin.rdbuf();
std::string s = ss.str();

In alternativa, si può anche utilizzare un istreambuf_iterator. Si dovrà misurare se questo o il modo di cui sopra è più veloce -. Non so

std::string s((istreambuf_iterator<char>(someStreamBuf)), 
               istreambuf_iterator<char>());

Si noti che someStreamBuf sopra vuole rappresentare un streambuf*, in modo da prendere il suo indirizzo a seconda dei casi. Da notare anche le parentesi aggiuntive attorno al primo argomento nell'ultimo esempio, in modo che esso non interpreta come una dichiarazione di funzione che restituisce una stringa e prendendo un iteratore e un altro puntatore a funzione ( "parse più irritante").

Altri suggerimenti

E ' davvero sepolto nella documentazione ...

Dato boost::asio::streambuf b, con size_t buf_size ...

boost::asio::streambuf::const_buffers_type bufs = b.data();
std::string str(boost::asio::buffers_begin(bufs),
                boost::asio::buffers_begin(bufs) + buf_size);

Un'altra possibilità con boost::asio::streambuf è quella di utilizzare in combinazione con boost::asio::buffer_cast<const char*>() boost::asio::streambuf::data() e boost::asio::streambuf::consume() in questo modo:

const char* header=boost::asio::buffer_cast<const char*>(readbuffer.data());
//Do stuff with header, maybe construct a std::string with std::string(header,header+length)
readbuffer.consume(length);

Questo non funzionerà con streambuf normale e potrebbe essere considerato sporco, ma sembra essere il modo più veloce di farlo.

Per boost::asio::streambuf è possibile trovare una soluzione come questa:

    boost::asio::streambuf buf;
    /*put data into buf*/

    std::istream is(&buf);
    std::string line;
    std::getline(is, line);

Stampare la stringa:

    std::cout << line << std::endl;

Si possono trovare qui: http: // www. boost.org/doc/libs/1_49_0/doc/html/boost_asio/reference/async_read_until/overload3.html

Si può anche ottenere i caratteri da utilizzare asio::streambuf std::basic_streambuf::sgetn:

asio::streambuf in;
// ...
char cbuf[in.size()+1]; int rc = in.sgetn (cbuf, sizeof cbuf); cbuf[rc] = 0;
std::string str (cbuf, rc);

Il motivo è possibile creare solo const_buffer da std :: string è perché std :: string in modo esplicito non supporta la scrittura diretta puntatore a base nel suo contratto. Si potrebbe fare qualcosa di cattivo, come ridimensionare la stringa in una certa dimensione, quindi const_cast la costanza da c_str () e trattarlo come un char * buffer di grezzo, ma questo è molto cattivo e ti porterà nei guai un giorno.

Io uso std :: vector per i miei buffer perché finché il vettore non ridimensionare (o si è attenti a che fare con il ridimensionamento), si può fare la scrittura diretta puntatore bene. Se ho bisogno di alcuni dei dati come uno std :: string, devo copiare fuori, ma il modo in cui ho a che fare con i miei buffer di lettura, tutto ciò che deve durare oltre la richiamata lettura deve essere copiato a prescindere.

Una risposta più semplice sarebbe quello di convertire in std::string e manipolarlo qualche cosa come questo

 std::string buffer_to_string(const boost::asio::streambuf &buffer)
 {
  using boost::asio::buffers_begin;
  auto bufs = buffer.data();
  std::string result(buffers_begin(bufs), buffers_begin(bufs) + buffer.size());
 return result;
}

Dare un codice molto conciso per il compito.

Credo che sia più simile a:


streambuf.commit( number_of_bytes_read );

istream istr( &streambuf );
string s;
istr >> s;

Non ho guardato nel codice basic_streambuf, ma credo che dovrebbe essere una sola copia nella stringa.

ho provato la prima risposta, ma ho un errore del compilatore quando si compila con "g ++ -std = c ++ 11" Che cosa ha funzionato per me è stato:

        #include <string>
        #include <boost/asio.hpp>
        #include <sstream>           
        //other code ...
        boost::asio::streambuf response;
        //more code
        std::ostringstream sline;
        sline << &response; //need '&' or you a compiler error
        std::string line = sline.str(); 

Questa compilato e corse.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top