2015-03-05 5 views
5

Si tratta di una buona idea per la lettura in un std::vector, o c'è qualche Gotcha qui:La lettura di un file in un vettore tutto in una volta

using namespace std; 
ifstream file("blah.dat", ios::binary); 

vector<T> v(N); 

file.read(static_cast<char*>(v.data()), N * sizeof(T)); 

fa il vector serie mi permetterà di fare questo per popolare un vettore ? Per motivi di semplicità, supponiamo che T sia un semplice vecchio tipo di dati.

+0

'size_of' ==' sizeof'? Ad ogni modo, sii consapevole che la dimensione di un oggetto in memoria non corrisponde necessariamente alla dimensione dell'oggetto quando viene scritto su un file (padding ecc.) - in realtà dipende da come l'oggetto è stato scritto per cominciare. –

+0

@KonradRudolph: Grazie, risolto. Se scritto in questo modo (cattivo per la portabilità, bene per il mio caso d'uso) scrivendo esplicitamente la memoria, dovrebbe essere letto in questo modo. Sono più curioso della parte 'v.data'. –

+0

Si dovrebbe specificare cosa 'T' è per ottenere risposte corrette. È un tipo POD? –

risposta

2

Qui non c'è un comportamento non definito se T è banalmente copiabile, quali sono certamente i POD. vector<T>::data è garantito per restituire un puntatore a un array contiguo di vector<T>::sizeT s e la rappresentazione dell'oggetto di un tipo banalmente copiabile T è una sequenza contigua di sizeof(T) byte (che potrebbe includere il riempimento interno).

Se i byte memorizzati in quello spazio non sono validi rappresentazioni oggetto T, è possibile ottenere un comportamento non definito quando si accede a loro. Esattamente quali sequenze di byte costituiscono una rappresentazione oggetto valida T è un po 'un'area grigia; per lo meno dovresti essere in grado di scrivere in modo portabile i byte sottostanti di un oggetto di un tipo banalmente copiabile in un file e rileggerli correttamente nei byte sottostanti di un oggetto dello stesso tipo.

Per l'amor di paranoia, probabilmente sarei messo:

static_assert(std::is_trivially_copyable<T>(), 
       "NO NO NO - T MUST BE TRIVIALLY COPYABLE!"); 

prima della file.read per future-proofing.

0

Non sono tenuti a farlo, in realtà quello che si suppone di fare (dal momento che il C++ originale) è questo

std::ifstream file("foo.txt"); 
file >> std::noskipws;   // use this line so that whitespace won't be skipped 
std::vector<char> buffer(std::istream_iterator<char>(file), 
         std::istream_iterator<char>()); 

La ragione per cui non si dovrebbe fare a modo tuo è perché non ha senso che un oggetto viva in un file (almeno in C++). I file contengono solo caratteri, che vengono quindi formattati da operator>> per creare oggetti. Lo standard consente al compilatore di fare cose davvero strane ad un oggetto (specialmente quando RTTI è abilitato) che rende inutile "salvare" un oggetto su un file. Stai molto meglio semplicemente creando il tuo formato di serializzazione per questo.

+2

'std :: istreambuf_iterator '. Il tuo esempio salterà lo spazio bianco. – user657267

+0

Cosa succede se non è un vettore di 'char'? Inoltre, il file è in binario. Puoi darmi qualche motivo per cui non dovrei farlo? –

+0

@ user657267 Vedere la mia modifica per quella correzione – randomusername

1

Sembra che si trarrebbe vantaggio da un file mappato in memoria. Boost fornisce due implementazioni, quindi non devi scherzare con mmap() direttamente.

Utilizzando boost.iostreams:

#include <boost/iostreams/device/mapped_file.hpp> 

boost::iostreams::mapped_file_source file("blah.dat"); 
std::size_t size = file.size()/sizeof(T); 
const T * ptr = reinterpret_cast<const T*>(file.data()); 
for (std::size_t i=0; i<size; ++i) 
    std::cout << ptr[i] << std::endl; 

È inoltre possibile utilizzare boost.interprocess, ma richiede più codice per essenzialmente la stessa funzionalità.

Il vantaggio principale è che non si alloca memoria per accedere al file, verrà caricato su richiesta al momento dell'accesso ai dati. I dati stessi vivranno in cache/pagine bufferizzate, quindi non occupano più memoria (vengono scartati se il sistema ha bisogno di memoria per qualcos'altro.)

+0

Un modo per controllare la dimensione della cache? –

+0

No, questo è tutto gestito dal sistema operativo; tipicamente userà tutte le pagine libere come cache/buffer, dal momento che non c'è molto da guadagnare lasciando la RAM inutilizzata. Cioè, se il tuo sistema ha 8 GB e viene utilizzato solo 1,5 GB, il sistema operativo sarà disponibile per il caching da 6,5 ​​GB. – DanielKO

+0

Oh: ancora una domanda: se due processi tentano di eseguire una sola lettura in mmap sullo stesso file, il file verrà caricato due volte? o il sistema operativo è abbastanza intelligente da mapparlo solo una volta? –