concatenar - copiar cadena de caracteres en c++
Obtener un istream de un char* (6)
¿Has probado std :: istrstream? http://stdcxx.apache.org/doc/stdlibref/istrstream.html
Técnicamente, creo que está en desuso, pero sigue siendo parte de la norma.
Tengo un char * y la longitud de datos que estoy recibiendo de una biblioteca, y necesito pasar los datos a una función que tome un istream.
Sé que puedo crear una cadena de caracteres, pero eso copiará todos los datos. Y también, los datos seguramente tendrán 0 ya que es un archivo zip, y al crear una cadena de caracteres los tomará hasta el primer 0, creo.
¿Hay alguna forma de crear un istream a partir de un carácter * y su tamaño sin copiar todos los datos?
Aquí hay un método no obsoleto que se encuentra en la web , le hace derivar su propia clase std::streambuf
, pero parece fácil y funciona:
#include <iostream>
#include <istream>
#include <streambuf>
#include <string>
struct membuf : std::streambuf
{
membuf(char* begin, char* end) {
this->setg(begin, begin, end);
}
};
int main()
{
char buffer[] = "I''m a buffer with embedded nulls/0and line/n feeds";
membuf sbuf(buffer, buffer + sizeof(buffer));
std::istream in(&sbuf);
std::string line;
while (std::getline(in, line)) {
std::cout << "line: " << line << "/n";
}
return 0;
}
Qué salidas:
line: I''m a buffer with embedded nullsand line
line: feeds
La única forma portátil (simple) incluye hacer la copia:
std::istringstream ss(std::string(buf,len));
De hecho, es probable que esto copie los datos dos veces, una vez para crear la string
y una vez para crear el istringstream
. (Quizás C ++ 11 pueda evitar una de las copias a través de un constructor de movimiento; no estoy seguro).
Sin embargo, si tiene suerte, su implementación de C ++ le permitirá hacer esto:
std::istringstream ss;
ss.rdbuf()->pubsetbuf(buf,len);
Bajo GNU C ++ (y, creo, algunas otras implementaciones), esto creará la cadena de caracteres sin copiar los datos. Pero este es un comportamiento "definido por la implementación" de acuerdo con la especificación. (Ver también esta pregunta ).
Al incluir el parámetro len
, se asegura de que ambos no tendrán problemas con los caracteres nulos.
La única forma portátil de hacer lo que quiere es implementar su propia subclase de stringbuf
y usarla para inicializar la cadena de caracteres. No para los débiles de corazón.
Necesitaba una solución que admita tellg
y seekg
y no requería refuerzo.
char_array_buffer
de here dio un punto de partida.
byte_array_buffer.h:
#include <cstdio>
#include <string>
#include <list>
#include <fstream>
#include <iostream>
//
// http://www.mr-edd.co.uk/blog/beginners_guide_streambuf
//
class byte_array_buffer : public std::streambuf
{
public:
byte_array_buffer(const uint8_t *begin, const size_t size);
private:
int_type underflow();
int_type uflow();
int_type pbackfail(int_type ch);
std::streamsize showmanyc();
std::streampos seekoff ( std::streamoff off, std::ios_base::seekdir way,
std::ios_base::openmode which = std::ios_base::in | std::ios_base::out );
std::streampos seekpos ( std::streampos sp,
std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
// copy ctor and assignment not implemented;
// copying not allowed
byte_array_buffer(const byte_array_buffer &);
byte_array_buffer &operator= (const byte_array_buffer &);
private:
const uint8_t * const begin_;
const uint8_t * const end_;
const uint8_t * current_;
};
byte_array_buffer.cpp:
#include "byte_array_buffer.h"
#include <cassert>
byte_array_buffer::byte_array_buffer(const uint8_t *begin, const size_t size) :
begin_(begin),
end_(begin + size),
current_(begin_)
{
assert(std::less_equal<const uint8_t *>()(begin_, end_));
}
byte_array_buffer::int_type byte_array_buffer::underflow()
{
if (current_ == end_)
return traits_type::eof();
return traits_type::to_int_type(*current_);
}
byte_array_buffer::int_type byte_array_buffer::uflow()
{
if (current_ == end_)
return traits_type::eof();
return traits_type::to_int_type(*current_++);
}
byte_array_buffer::int_type byte_array_buffer::pbackfail(int_type ch)
{
if (current_ == begin_ || (ch != traits_type::eof() && ch != current_[-1]))
return traits_type::eof();
return traits_type::to_int_type(*--current_);
}
std::streamsize byte_array_buffer::showmanyc()
{
assert(std::less_equal<const uint8_t *>()(current_, end_));
return end_ - current_;
}
std::streampos byte_array_buffer::seekoff ( std::streamoff off, std::ios_base::seekdir way,
std::ios_base::openmode which )
{
if (way == std::ios_base::beg)
{
current_ = begin_ + off;
}
else if (way == std::ios_base::cur)
{
current_ += off;
}
else if (way == std::ios_base::end)
{
current_ = end_;
}
if (current_ < begin_ || current_ > end_)
return -1;
return current_ - begin_;
}
std::streampos byte_array_buffer::seekpos ( std::streampos sp,
std::ios_base::openmode which )
{
current_ = begin_ + sp;
if (current_ < begin_ || current_ > end_)
return -1;
return current_ - begin_;
}
Pruebe las clases de fuente y receptor de matriz Boost.Iostreams.
http://www.boost.org/doc/libs/1_47_0/libs/iostreams/doc/index.html
Una solución no obsoleta utilizando Boost:
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/array.hpp>
using namespace boost::iostreams;
basic_array_source<char> input_source(my_ptr_to_char, byte_count);
stream<basic_array_source<char> > input_stream(input_source);
o incluso más simple:
#include <boost/interprocess/streams/bufferstream.hpp>
using namespace boost::interprocess;
bufferstream input_stream(my_ptr_to_char, byte_count);