Pregunta

¿Hay alguna forma de leer un número conocido de bytes, directamente en una cadena std ::, sin crear un búfer temporal para hacerlo?

por ejemplo, actualmente puedo hacerlo

boost::uint16_t len;
is.read((char*)&len, 2);
char *tmpStr = new char[len];
is.read(tmpStr, len);
std::string str(tmpStr, len);
delete[] tmpStr;
¿Fue útil?

Solución

std :: string tiene una función redimensionar que podría usar, o un constructor que hará lo mismo:

boost::uint16_t len;
is.read((char*)&len, 2);

std::string str(len, '\0');
is.read(&str[0], len);

Esto no se ha probado, y no sé si las cadenas deben tener almacenamiento contiguo.

Otros consejos

Puede usar una combinación de copy_n y un insert_iterator

void test_1816319()
{
    static char const* fname = "test_1816319.bin";
    std::ofstream ofs(fname, std::ios::binary);
    ofs.write("\x2\x0", 2);
    ofs.write("ab", 2);
    ofs.close();

    std::ifstream ifs(fname, std::ios::binary);
    std::string s;
    size_t n = 0;
    ifs.read((char*)&n, 2);
    std::istream_iterator<char> isi(ifs), isiend;
    std::copy_n(isi, n, std::insert_iterator<std::string>(s, s.begin()));
    ifs.close();
    _unlink(fname);

    std::cout << s << std::endl;
}

sin copia, sin hacks, sin posibilidad de desbordamiento, sin comportamiento indefinido.

Podría usar algo como getline:

#include <iostream>
#include <string>
using namespace std;

int main () {
  string str;
  getline (cin,str,' ');
}

Usaría un vector como el búfer.

boost::uint16_t len;
is.read((char*)&len, 2); // Note if this file was saved from a different architecture 
                         // then endianness of these two bytes may be reversed.

std::vector buffer(len);  // uninitialized.
is.read(&buffer[0], len);

std::string  str(buffer.begin(),buffer.end());

Aunque probablemente se saldrá con la suya usando una cadena como el búfer (como lo describe GMan). El estándar no garantiza que los miembros de una cadena se encuentren en ubicaciones consecutivas (así que verifique su implementación actual y ponga un gran comentario que necesita verificar cuando se transfiere a otro compilador / plataforma).

¿Estás optimizando la longitud del código o tratando de guardarte una copia aquí? ¿Qué tiene de malo el búfer temporal?

Yo diría que en realidad estás eludiendo las protecciones de la cadena tratando de escribir directamente, hazlo así. Si le preocupa el rendimiento de la copia en una cadena std :: porque ha identificado que de alguna manera afecta el rendimiento de su aplicación, trabajaría directamente con el char *.

EDITAR: Hacer más buscando ... inicializando std :: string desde char * sin copia

En la segunda respuesta, se dice de manera bastante plana que no se puede lograr lo que se busca lograr (es decir, llenar una cadena std :: sin una iteración sobre el carácter * para copiar).

Eche un vistazo a su rutina de carga (¿quizás publicarla aquí?) y minimice las asignaciones: nuevo y eliminar ciertamente no son gratuitos, por lo que al menos puede ahorrar algo de tiempo si no tiene que volver a crear el búfer constantemente . Siempre me parece útil borrarlo al configurar el búfer en 0 o anular la terminación del primer índice de la matriz en cada iteración, pero puede eliminar rápidamente ese código en interés del rendimiento una vez que esté seguro de su algoritmo.

Una manera fácil sería:

std::istream& data
const size_t dataSize(static_cast<size_t>(data.rdbuf()->in_avail()));
std::string content;
content.reserve( dataSize);
data.read(&content[0], dataSize);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top