Рассматривая следующий пример сериализации, как boost справляется с сохранением данных, когда эти данные являются константными, а функция сериализации не является константной функцией?
Есть ли где-нибудь конст-бросок?
struct Settings
{
Settings();
uint32_t buffers_size;
uint32_t messages;
};
template < class Archive >
void serialize(Archive& ar, Settings& settings, unsigned int /*version*/)
{
using boost::serialization::make_nvp;
ar
& make_nvp< uint32_t >("buffers_size", settings.buffers_size )
& make_nvp< uint32_t >("messages", settings.messages);
}
Насколько я могу судить, константность действительно отбрасывается перед сохранением объекта. Я думаю, что соответствующий код находится в oserializer.hpp
:
template<class Archive, class T>
BOOST_DLLEXPORT void oserializer<Archive, T>::save_object_data(
basic_oarchive & ar,
const void *x
) const {
// make sure call is routed through the highest interface that might
// be specialized by the user.
BOOST_STATIC_ASSERT(boost::is_const< T >::value == false);
boost::serialization::serialize_adl(
boost::serialization::smart_cast_reference<Archive &>(ar),
* static_cast<T *>(const_cast<void *>(x)),
version()
);
}
Перед вызовом этого метода ссылка на сериализованный объект превращается в const void *
, соответствующий второму параметру здесь. Константность этого указателя отбрасывается, а результирующий указатель приводится к соответствующему типу указателя, который затем разыменовывается.
Это поднимает вопрос о возможности вызова неопределенного поведения при попытке сериализации const
объект: если serialize
Функция member / free каким-то образом изменяет объект, а затем создает const
объект и сохранение его в архиве будет неопределенным поведением и останется незамеченным во время компиляции!
Если вы разделите функцию на save
а также load
тогда вы должны отметить save
как const
, что предотвращает случайное изменение объекта.
Других решений пока нет …