EDIT: новый ответ добавлен ниже для решения реальной проблемы.
Ваш вопрос подразумевает, что вы неоднократно десериализуете один и тот же объект. Это косвенно, если это чисто или нет. Если, например, у вас есть шахматная доска, вы хотели бы синхронизировать начальное положение фигур (чтобы продолжить с последней сохраненной игры). Чтобы сообщать ходы во время игры, может быть лучше отправлять отдельные ходы в виде отдельных объектов (которые затем применяются к объекту доски после получения) вместо передачи всего объекта доски, который будет передавать только то, что изменилось если он уже "инициализирован". Таким образом, вы можете сначала проверить ввод и игнорировать недопустимые ходы. В любом случае, я просто хотел упомянуть об этом, давайте двигаться дальше.
Если у вас есть объект, который может быть синхронизирован несколько раз, с данными-членами, которые нужно передать только один раз, позвольте объекту решить, является ли он «инициализированным» или нет (и, следовательно, нужно ли ему передавать все или только подмножество) с помощью флага (который не сериализуется).
Затем вы можете проверить флаг в коде сериализации объекта, как и в опубликованном вами коде (за исключением того, что флаг не является параметром метода сериализации, а является переменной-членом объекта, который вы де/сериализуете). Если флаг установлен, де/сериализуйте все и сбросьте флаг. И клиент, и сервер должны иметь одинаковое состояние флага, иначе сериализация прерывается.
В качестве альтернативы вы можете сначала сериализовать флаг, чтобы сообщить получателю, как должна выполняться десериализация (например, один бит для каждой группы данных).
Имейте в виду, что десериализация должна соответствовать сериализации; Вы должны извлечь одни и те же объекты в том же порядке, в котором они были сериализованы.
Однако вы можете сериализовать полиморфные классы, если они сериализуются на том же уровне в иерархии классов, что и десериализованные (если есть сомнения, приведите к базовому указателю при отправке и десериализуйте также через базовый указатель).
Что касается вашего второго вопроса, вы ищете ненавязчивая сериализация. Ненавязчивая сериализация вызывает автономные функции и передает сериализуемый объект в качестве параметра (так сериализуются std::vector и boost::shared_ptr). Вы можете использовать BOOST_SERIALIZATION_SPLIT_FREE
, чтобы разделить автономную функцию serialize()
на save()
и load()
. Для навязчивой сериализации это BOOST_SERIALIZATION_SPLIT_MEMBER
.
Чтобы написать обобщенную функцию де/сериализации (которая, например, передает объекты по сети), вы можете использовать шаблоны:
template<typename T>
void transmit( const T& data ) {
// ...
archive << data
socket << archive_stream;
}
Ограничение этого метода состоит в том, что получатель должен знать, какой объект был отправлен. Если вы хотите отправлять случайные объекты, сделайте их полиморфными:
IData* data = 0;
archive >> data;
switch( data->type() ) {
case TYPE_INIT:
return dispatch( static_cast<Board*>(data) );
case TYPE_MOVE:
return dispatch( static_cast<Move*>(data) );
case TYPE_CHAT:
return dispatch( static_cast<ChatMsg*>(data) );
}
ОБНОВЛЕНИЕ: если вам нужно контролировать поведение ваших (настраиваемых) методов/функций сериализации на основе состояния, неизвестного сериализуемым типам, вы можете реализовать свой собственный архивный класс, который содержит состояние. Затем функции сериализации могут запрашивать состояние и действовать соответствующим образом.
Это состояние (или соответствующая замена) также должно быть сериализовано, чтобы указать, как данные должны быть десериализованы. Например, это «другое поведение» функций сериализации может быть своего рода сжатием, а состояние — типом используемого сжатия.
Вот минимальный пример пользовательского выходного архива. Для получения дополнительной информации вы можете прочитать Наследование из существующего архива и покопайтесь в источниках буста.
Учитывая класс, который вы не можете изменить:
struct Foo {
Foo() : i(42), s("foo") {}
int i;
std::string s;
};
Вы хотите сериализовать i
и/или s
на основе условия, неизвестного классу. Вы можете создать оболочку для его сериализации и добавления состояния, но это не сработает, если объект находится внутри вектора (или другого класса, если на то пошло).
Вместо этого может быть проще сообщить архиву о состоянии:
#include <boost/archive/text_oarchive.hpp>
// using struct to omit a bunch of friend declarations
struct oarchive : boost::archive::text_oarchive_impl<oarchive>
{
oarchive(std::ostream& os, unsigned flags=0)
: boost::archive::text_oarchive_impl<oarchive>(os,flags),mask(0){}
// forward to base class
template<class T> void save( T& t ) {
boost::archive::text_oarchive_impl<oarchive>::save(t);
}
// this is the 'state' that can be set on the archive
// and queried by the serialization functions
unsigned get_mask() const { return mask; }
void set_mask(unsigned m) { mask = m; }
void clear_mask() { mask = 0; }
private:
unsigned mask;
};
// explicit instantiation of class templates involved
namespace boost { namespace archive {
template class basic_text_oarchive<oarchive>;
template class text_oarchive_impl<oarchive>;
template class detail::archive_serializer_map<oarchive>;
} }
// template implementations (should go to the .cpp)
#include <boost/archive/impl/basic_text_oarchive.ipp>
#include <boost/archive/impl/text_oarchive_impl.ipp>
#include <boost/archive/impl/archive_serializer_map.ipp>
Теперь состояние для установки и запроса:
enum state { FULL=0x10, PARTIAL=0x20 };
И метод для установки состояния (это просто очень простой пример):
oarchive& operator<<(oarchive& ar, state mask) {
ar.set_mask(ar.get_mask()|mask);
return ar;
}
Наконец, (ненавязчивая) функция сериализации:
namespace boost { namespace serialization {
template<class Archive>
void save(Archive & ar, const Foo& foo, const unsigned int version)
{
int mask = ar.get_mask(); // get state from the archive
ar << mask; // serialize the state! when deserializing,
// read the state first and extract the data accordingly
if( mask & FULL )
ar << foo.s; // only serialize s if FULL is set
ar << foo.i; // otherwise serialize i only
ar.clear_mask(); // reset the state
}
} } // boost::serialization
BOOST_SERIALIZATION_SPLIT_FREE(Foo)
И это можно использовать следующим образом:
int main() {
std::stringstream strm;
oarchive ar(strm);
Foo f;
ar << PARTIAL << f << FULL << f;
std::cout << strm.str();
}
Цель этого примера — просто проиллюстрировать принцип. Это слишком просто для производственного кода.
person
Anonymous Coward
schedule
28.12.2012