2013-11-25 3 views
8

У меня есть древовидная структура, которая должна быть сериализована. Типичная структура, причем каждый узел имеет parent членов и children векторов. parent является исходным указателем на класс, и children: vector s shared_ptr s. Теперь кажется, что сериализация работает нормально, но de -сериализация оставляет parent членов неинициализированных (указывает на 0xcccccccc или 0x00000000).boost :: сериализация и циклическая десериализация ссылок

В parent членах загружаются, когда фактический родительский объект еще не закончил десериализации, то есть ребенок parent элемента загружается через запрос десериализации родителя children. Поскольку это циклично, мне было интересно, нужно ли мне принимать специальные меры для его работы.

Спасибо за помощь.

Update: Это как моя функция сериализация выглядит следующим образом:

template <typename Archive> 
void serialize(Archive& archive, GameCore::GameObject& t, const unsigned int version) 
{ 
    archive & boost::serialization::base_object<GameCore::Object>(t); 
    archive & boost::serialization::base_object<GameCore::Updatable>(t); 
    archive & t.parent; 
    archive & t.transform; 
    archive & t.components; 
    archive & t.children; 
} 

Если я закомментировать archive & t.children, parent получает правильно заполнены.

Обновление 2: Хорошо, мне удалось превратить это в минимальный образец, который представляет проблему. Необходимо скомпилировать:

#include <boost\archive\binary_oarchive.hpp> 
#include <boost\archive\binary_iarchive.hpp> 
#include <fstream> 
#include <memory> 
#include <vector> 

class A 
{ 
public: 
    A() {} 
    A(const A& rhs) = delete; 

    int someInt = 0; 
    A* parent = nullptr; 
    std::vector<A*> children; 

    template <class Archive> 
    void serialize(Archive& archive, const unsigned int version) 
    { 
     archive & someInt; 
     archive & parent; 
     int count = children.size(); 
     archive & count; 
     children.resize(count); 
     for (int i = 0; i < count; ++i) 
     { 
      A* ptr = children[i]; 
      archive & ptr; 
      children[i] = ptr; 
     } 
    } 
}; 


int main() 
{ 
    A* newA = new A(); 
    newA->someInt = 0; 

    A* newPtr = new A(); 
    newPtr->someInt = 5; 
    newPtr->parent = newA; 

    newA->children.push_back(newPtr); 

    // Save. 
    std::ofstream outputFile("test", std::fstream::out | std::fstream::binary); 
    if (outputFile.is_open()) 
    { 
     boost::archive::binary_oarchive outputArchive(outputFile); 

     // Serialize objects. 
     outputArchive << newA; 
     outputFile.close(); 
    } 

    delete newA; 
    delete newPtr; 

    A* loadedPtr = nullptr; 

    // Load. 
    std::ifstream inputFile("test", std::fstream::binary | std::fstream::in); 
    if (inputFile && inputFile.good() && inputFile.is_open()) 
    { 
     boost::archive::binary_iarchive inputArchive(inputFile); 

     // Load objects. 
     inputArchive >> loadedPtr; 
     inputFile.close(); 
    } 

    return 0; 
} 

Пройдите код. Ребенок parent остается нулевым, всегда.

+0

Если кто-нибудь, * кто-то может реплицировать эту проблему, пожалуйста, дайте мне знать, потому что это сводит меня с ума! –

+0

FWIW: программа в обновлении 2 (плюс некоторые утверждения для проверки) [работает правильно в Coliru] (http://coliru.stacked-crooked.com/a/69a02441a7048015), поэтому проблема в вашем конце. – Casey

+0

Тогда что, черт возьми, я делаю неправильно? Я тестировал это на двух машинах, двух разных сборках Boost ... Может, я ошибаюсь? –

ответ

3

Alright, видимо, я пал жертвой другого несчастного жука. У Boost 1.55 еще нет рабочей библиотеки сериализации для VS2013, согласно latest Boost release page. Разговор о потраченном впустую времени ...

Известные ошибки с Visual Studio 2013/Visual C++ 12

Visual Studio 2013 был выпущен довольно поздно в процессе выпуска, поэтому существует несколько нерешенных вопросов. К ним относятся:

Сериализация не может быть скомпилирована из-за отсутствия.

+0

Я не вижу, где вы получили эту информацию. Можете ли вы указать/ссылаться на конкретное местоположение документа, которое говорит вам, что нет библиотеки сериализации для VS2013? (Я вижу, что VC12 еще не указан в _ (дополнительных) тестовых компиляторах, но это другое дело) – sehe

+0

Обновлен мой ответ с цитатой, из верхней части страницы, с которой я связан. –

0

Если вы используете Boost Serialization, все должно работать из коробки. Вы класса serialize может выглядеть так:

#include <boost/serialization/vector.hpp> 
void serialize (Archive&ar, unsigned int version) 
{ 
    //declare possible derived types of nodes 
    ar & parent; 
    ar & children; 
} 

Архив будет содержать указатели хэширования, чтобы он не создавал каждый элемент более одного раза.

Одна важная деталь: если ваши узлы могут иметь какой-либо производный тип, вам нужно учить архив, какие типы ожидать в // месте, Подробнее см. В документации по ускорению сериализации производных типов с помощью указателей на базовый тип.

Если вы уверены, что ваша древовидная структура правильная и автономная (корень имеет NULL в качестве родителя, все остальные узлы являются «дочерними» из их соответствующих «родительских» и т. Д.), Чем вы можете упорядочить код немного больше эффективно:

#include <boost/serialization/vector.hpp> 
void serialize (Archive&ar, unsigned int version) 
{ 
    //declare possible derived types of nodes (either here or at archive creation point)   
    ar & children; 
    if (typename Archive::is_loading()) 
    { 
      for (auto child : children) 
      child->parent = this; 
    } 
} 

(Предполагаю, что вы установите «parent» в NULL в конструкторе).

Я не тестировал этот код с VS 2013.

1

У меня была такая же проблема в прошлом, и я не нашел твердого решения из-за-коробки. Но следующий небольшой взлом работает отлично - вы можете отдельно определять функции сериализации и де-сериализации (не используя шаблон по умолчанию и & -оператора):

//! Serialization 
void A::serialize(xml_oarchive& ar, const unsigned int version) 
{ 
    ar << value; 
} 
//! De-serialization 
void A::serialize(xml_iarchive& ar, const unsigned int version) 
{ 
    ar >> value; 
} 

и после этого вы можете указать восстановление указателя на родительский объект в методе десериализации, как следующее:

//! Serialization 
void A::serialize(xml_oarchive& ar, const unsigned int version) 
{ 
    ar << children; 
} 
//! De-serialization 
void A::serialize(xml_iarchive& ar, const unsigned int version) 
{ 
    ar >> children; 
    for(var child: children) 
     child->parent = this; 
} 
+0

Какую версию буксировки вы использовали? Я попробовал это на работе с предварительно построенным 1.54 для x64, и указатель «parent» был заполнен правильно. Кстати, я использую ваше обходное решение на самом деле, но я также встретил ошибку в местах, где указатель сначала десериализован в порядке, а затем десериализован в совершенно другом месте (без простого обходного пути вроде этого), при этом второй заканчивается нулевым или неинициализированный. –

+0

Я думаю, что это был рост 1.33, но я не уверен. btw Я протестировал ваш код с 1.54 и 1.55 на gcc (mingw64), он работает правильно. И я также проверил подсчет ссылок по умолчанию в boost serialization, он отлично работает с древовидной структурой, двойным списком и циклическим списком - все указатели на родительские элементы восстанавливаются правильно. – infra

+0

Да, это проблема VC++ 12. –

Смежные вопросы