2013-12-15 9 views
5

Sto provando a serializzare e deserializzare i puntatori C non elaborati e i relativi dati, con l'esempio seguente. Sembra serializzare bene, ma non sono sicuro di come farlo deserializzare - si blocca solo con un'eccezione di violazione di accesso alla memoria quando lo deserializzo. Suppongo sia perché non sa come deserializzare, ma dove lo specificherò?serializzazione boost, deserializzazione di array C grezzi

Utilizzando un vettore non è un'opzione, in grandissime dati primitivi importi è dolorosamente lento

#include <stdint.h> 
#include <string> 
#include <iostream> 
#include <fstream> 
#pragma warning (push) 
#pragma warning(disable : 4244) 
#include <boost/serialization/serialization.hpp> 
#include <boost/serialization/vector.hpp> 
#include <boost/serialization/string.hpp> 
#include <boost/serialization/array.hpp> 
#include <boost/archive/binary_oarchive.hpp> 
#include <boost/archive/binary_iarchive.hpp> 
#pragma warning (pop) 

struct Monkey 
{ 
    uint32_t num; 
    float* arr; 

}; 


namespace boost 
{ 
    namespace serialization 
    { 
     template<class Archive> 
     void serialize(Archive & ar, Monkey& m, const unsigned int version) 
     { 
      ar & m.num; 
      ar & make_array<float>(m.arr, m.num); 
     } 
    } 
} 


int _tmain(int argc, _TCHAR* argv[]) 
{ 
    const char* name = "monkey.txt"; 

    { 
     Monkey m; 
     m.num = 10; 
     m.arr = new float[m.num]; 
     for (uint32_t index = 0; index < m.num; index++) 
      m.arr[index] = (float)index; 

     std::ofstream outStream(name, std::ios::out | std::ios::binary | std::ios::trunc); 
     boost::archive::binary_oarchive oar(outStream); 
     oar << (m); 
    } 

    Monkey m; 
    std::ifstream inStream(name, std::ios::in | std::ios::binary);  
    boost::archive::binary_iarchive iar(inStream); 
    iar >> (m); 

    return 0; 
} 

risposta

8

lo consiglio vivamente di utilizzare std::array o std::vector qui, perché ... si incasinato questo in su :)

Per cominciare, Monkey non inizializza i suoi membri. Quindi, il caricamento finisce per fare un load_binary a qualsiasi valore del puntatore m.arr avvenuto. Come ti aspetteresti che la deserializzazione "sappia" che hai bisogno di allocare memoria per questo? È necessario raccontarla:

template<class Archive> 
    void serialize(Archive & ar, Monkey& m, const unsigned int version) 
    { 
     ar & m.num; 
     if (Archive::is_loading::value) 
     { 
      assert(m.arr == nullptr); 
      m.arr = new float[m.num]; 
     } 
     ar & make_array<float>(m.arr, m.num); 
    } 

Ora, facciamo Monkey un po 'meno pericoloso (con l'aggiunta di inizializzazione e distruzione, e, forse più importante, che vieta la semantica di copia):

struct Monkey 
{ 
    uint32_t num; 
    float* arr; 

    Monkey() : num(0u), arr(nullptr) {} 

    Monkey(Monkey const&) = delete; 
    Monkey& operator=(Monkey const&) = delete; 
    ~Monkey() { delete[] arr; } 
}; 

Ora , si può vedere il lavoro:

#include <iostream> 
#include <fstream> 
#pragma warning(disable: 4244) 
#include <boost/serialization/serialization.hpp> 
#include <boost/archive/binary_oarchive.hpp> 
#include <boost/archive/binary_iarchive.hpp> 

struct Monkey 
{ 
    uint32_t num; 
    float* arr; 

    Monkey() : num(0u), arr(nullptr) {} 

    Monkey(Monkey const&) = delete; 
    Monkey& operator=(Monkey const&) = delete; 
    ~Monkey() { delete[] arr; } 
}; 

namespace boost 
{ 
    namespace serialization 
    { 
     template<class Archive> 
     void serialize(Archive & ar, Monkey& m, const unsigned int version) 
     { 
      ar & m.num; 
      if (Archive::is_loading::value) 
      { 
       assert(m.arr == nullptr); 
       m.arr = new float[m.num]; 
      } 
      ar & make_array<float>(m.arr, m.num); 
     } 
    } 
} 

int main(int argc, char* argv[]) 
{ 
    const char* name = "monkey.txt"; 
    { 
     Monkey m; 
     m.num = 10; 
     m.arr = new float[m.num]; 
     for (uint32_t index = 0; index < m.num; index++) 
      m.arr[index] = (float)index; 

     std::ofstream outStream(name, std::ios::out | std::ios::binary | std::ios::trunc); 
     boost::archive::binary_oarchive oar(outStream); 
     oar << (m); 
    } 

    Monkey m; 
    std::ifstream inStream(name, std::ios::in | std::ios::binary); 
    boost::archive::binary_iarchive iar(inStream); 
    iar >> (m); 

    std::copy(m.arr, m.arr + m.num, std::ostream_iterator<float>(std::cout, ";")); 
} 

Stampe

01.235.
0;1;2;3;4;5;6;7;8;9; 

Live on Coliru

+1

Ho iniziato a scrivere la mia risposta ma @sehe ha messo tutto il codice e tutti i problemi già.Posso solo aggiungere il mio riassunto, semplicemente riformulando ciò che è qui dentro: il tuo vero problema non è la deserializzazione in sé, ma la gestione della memoria. Non hai specificato come la struct Monkey assegna, copia o rilascia la memoria che usa. Sehe ha fornito due modi puliti per risolvere questo problema di gestione della memoria (utilizzare il vettore o aggiungere/eliminare copiatrice, lettore, ecc.). –

2

Mentre deserializzazione, m.arr non è inizializzata ad un array di 10 carri, ma ad un float*.

Marca Monkey::arr un std::vector<float> anziché float*. La serializzazione boost sa come serializzare e deserializzare tutti i contenitori dalla libreria standard C++.

+0

Come/dove posso allocare questa memoria, dato che m.num potrebbe essere un qualsiasi numero arbitrario che non so fino a che deserializzare esso? – KaiserJohaan

+0

Non lo so. Ma potresti rendere 'Monkey :: arr' un' std :: vector 'invece di' float * '. La serializzazione boost sa come serializzare e deserializzare tutti i contenitori dalla libreria standard C++. – Oswald

+0

Purtroppo non posso farlo; come ho scritto prima del frammento di codice, ho a che fare con grandi quantità di dati (molte mesh 3D e dati di immagine) ed è troppo lento per deserializzare (minuti!) – KaiserJohaan