2013-12-15 9 views
5

Próbuję serializować i deserializować surowe wskaźniki C i ich dane, korzystając z poniższego przykładu. Wydaje się serializować, ale nie mam pewności, jak sprawić, by była deserializacją - po prostu rozbija się o wyjątek naruszenia dostępu do pamięci po deserializacji. Przypuszczam, że dzieje się tak dlatego, że nie wie, jak go przekształcić, ale gdzie mam to określić?Serializacja wzmocnienia, deserializacja surowych macierzy C

Stosując wektor nie jest opcją, w bardzo dużych danych pierwotnych kwot jest boleśnie powolny

#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; 
} 

Odpowiedz

8

ja serdecznie polecam użyć std::array lub std::vector tutaj, bo ... no to pomieszane :)

Na początek, Monkey nie zainicjować jego członków. Tak więc ładowanie kończy się robieniem load_binary do dowolnej wartości wskaźnika, który miałby m.arr. Jak można oczekiwać, że deserializacja "wiedzieć", że trzeba przydzielić pamięci do tego? Trzeba powiedzieć, że:

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

Teraz zróbmy Monkey nieco mniej niebezpieczne (dodając inicjalizacji i zniszczenia, a może przede wszystkim, zakazujące semantykę kopia):

struct Monkey 
{ 
    uint32_t num; 
    float* arr; 

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

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

teraz widać to działa:

#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, ";")); 
} 

Drukuje

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

Live on Coliru

+1

Zacząłem pisać własną odpowiedź, ale @sehe już wszystkie kod i wszystkie problemy.Mogę tylko dodać moje podsumowanie, po prostu zmieniając to, co jest tutaj: twoim prawdziwym problemem nie jest deserializacja jako taka, ale zarządzanie pamięcią. Nie określono, w jaki sposób struct Monkey przydziela, kopiuje lub zwalnia pamięć, której używa. Sehe dostarczył dwa czyste sposoby na rozwiązanie tego problemu zarządzania pamięcią (albo wektor użytkowy, albo dodaj/usuń ctor, dtor itd.). –

2

Podczas deserializacji, m.arr nie jest inicjowany do tablicy 10 pływaków, ale do float*.

Utwórz Monkey::arr jako std::vector<float> zamiast float*. Zwiększona serializacja wie, jak serializować i deserializować wszystkie pojemniki ze standardowej biblioteki C++.

+0

Jak/gdzie mogę przeznaczyć tę pamięć, skoro m.num może być dowolną liczbę arbitralne, że aż nie wiem ja deserializowania go? – KaiserJohaan

+0

Nie wiem. Ale możesz zrobić 'Monkey :: arr' an' std :: vector 'zamiast' float * '. Zwiększona serializacja wie, jak serializować i deserializować wszystkie pojemniki ze standardowej biblioteki C++. – Oswald

+0

Nie mogę tego zrobić niestety; jak napisałem przed fragmentem kodu, mam do czynienia z dużymi ilościami danych (wiele siatek i danych obrazu) i jest zbyt wolny, aby deserializować go (minuty!). – KaiserJohaan