web-dev-qa-db-fra.com

Copier le contenu d'un streambuf dans une chaîne

Apparemment, boost::asio::async_read n'aime pas les chaînes, car la seule surcharge de boost::asio::buffer me permet de créer des const_buffers. Je suis donc obligé de tout lire dans un streambuf.
Maintenant, je veux copier le contenu du streambuf dans une chaîne, mais il ne prend apparemment en charge que l'écriture dans char * (sgetn()), la création d'un flux de sortie avec le streambuf et l'utilisation de getline()

Existe-t-il un autre moyen de créer une chaîne avec le contenu de streambufs sans copier excessivement?

30
tstenner

Je ne sais pas si cela compte comme " copie excessive ", mais vous pouvez utiliser un stringstream:

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

Comme, pour tout lire de stdin en chaîne, faites

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

Vous pouvez également utiliser un istreambuf_iterator. Vous devrez mesurer si cette méthode ou celle ci-dessus est plus rapide - je ne sais pas.

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

Notez que someStreamBuf ci-dessus est censé représenter un streambuf*, prenez donc son adresse comme il convient. Notez également les parenthèses supplémentaires autour du premier argument dans le dernier exemple, afin qu'il ne soit pas interprété comme une déclaration de fonction renvoyant une chaîne et prenant un itérateur et un autre pointeur de fonction ("analyse la plus frustrante").

44

C'est vraiment enterré dans la documentation ...

Étant donné boost::asio::streambuf b, avec 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);
37
Sean DeNigris

Une autre possibilité avec boost::asio::streambuf consiste à utiliser boost::asio::buffer_cast<const char*>() conjointement avec boost::asio::streambuf::data() et boost::asio::streambuf::consume() comme ceci:

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

Cela ne fonctionnera pas avec les strates normales et pourrait être considéré comme sale, mais cela semble être le moyen le plus rapide de le faire.

24
tstenner

Pour boost::asio::streambuf, vous pouvez trouver une solution comme celle-ci: 

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

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

Imprimez la chaîne:

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

Vous trouverez ici: http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/reference/async_read_until/overload3.html

13
iericzhou

On peut aussi obtenir les caractères de asio::streambuf en utilisant 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);
1
ArtemGr

La raison pour laquelle vous ne pouvez créer que const_buffer à partir de std :: string est que std :: string ne prend pas explicitement en charge l'écriture directe basée sur un pointeur dans son contrat. Vous pouvez faire quelque chose de mal, comme redimensionner votre chaîne à une certaine taille, puis const_cast la constness de c_str () et la traiter comme un char * buffer brut, mais c'est très méchant et vous causera des ennuis un jour.

J'utilise std :: vector pour mes tampons car tant que le vecteur ne redimensionne pas (ou que vous prenez bien soin de le redimensionner), vous pouvez très bien écrire directement avec un pointeur. Si j'ai besoin de certaines données en tant que std :: string, je dois les copier, mais la façon dont je gère mes mémoires tampon de lecture fait que tout ce qui doit durer au-delà du rappel en lecture doit être copié indépendamment.

0
user121826

Une réponse plus simple consisterait à le convertir en std::string et à le manipuler avec un peu de ce genre.

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

Donner un code très concis pour la tâche.

0
DevMac