Domanda

Esiste un modo per leggere un numero noto di byte, direttamente in una stringa std :: string, senza creare un buffer temporaneo per farlo?

ad esempio, attualmente posso farlo

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;
È stato utile?

Soluzione

std :: string ha una funzione ridimensiona che potresti usare, o un costruttore che farà lo stesso:

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

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

Questo non è testato e non so se le stringhe sono obbligate ad avere una memoria contigua.

Altri suggerimenti

Puoi usare una combinazione di copy_n e 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;
}

nessuna copia, nessun hack, nessuna possibilità di superamento, nessun comportamento indefinito.

Puoi usare qualcosa come getline:

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

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

Vorrei usare un vettore come buffer.

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

Anche se probabilmente riuscirai ad usare una stringa come buffer (come descritto da GMan). Lo standard non garantisce che i membri di una stringa si trovino in posizioni consecutive (quindi controlla la tua attuale implementazione e metti un grande commento che deve essere verificato quando esegui il porting su un altro compilatore / piattaforma).

Stai solo ottimizzando la lunghezza del codice o stai cercando di salvarti una copia qui? Cosa c'è che non va nel buffer temporaneo?

Direi che stai effettivamente aggirando le protezioni della stringa cercando di scrivere direttamente, fai così. Se sei preoccupato per le prestazioni della copia in una std :: string perché hai identificato che sta influenzando in qualche modo le prestazioni della tua applicazione, lavorerei direttamente con il carattere *.

EDIT: fare di più cercando ... inizializzazione std :: string from char * senza copia

Nella seconda risposta, si afferma piuttosto chiaramente che non è possibile ottenere ciò che si sta cercando di ottenere (ad es. popolare una stringa std :: string senza un'iterazione sul carattere * da copiare.)

Dai un'occhiata alla tua routine di caricamento (postala qui forse?) e riduci al minimo le allocazioni: le novità e le eliminazioni certamente non sono gratuite, quindi puoi almeno risparmiare un po 'di tempo se non devi ricreare costantemente il buffer . Trovo sempre utile cancellarlo memorizzando il buffer su 0 o null terminando il primo indice dell'array ogni iterazione ma puoi eliminare rapidamente quel codice nell'interesse delle prestazioni una volta che sei sicuro del tuo algoritmo.

Un modo semplice sarebbe:

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);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top