I'd like deserialization to fail when size of the array that I'm trying to deserialize to does not match the originally serialized array's size.
So far it only fails when arr1_size > arr2_size
and I want it to be arr1_size != arr2_size
:
#include <iostream>
#include <sstream>
#include <array>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/array.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
int main()
{
const size_t arr1_size = 4, arr2_size = 3;
std::stringstream ss;
// save
std::array<int, arr1_size> arr1;
boost::archive::text_oarchive oar(ss, boost::archive::no_header);
oar & arr1;
// load
std::array<int, arr2_size> arr2;
boost::archive::text_iarchive iar(ss, boost::archive::no_header);
iar & arr2; // throw on size inequality, please
}
I thought about:
serializing through std::vector
s and handling this myself, but that might lead to performance loss
checking arr2
afterwards (if it doesn't throw on arr1_size > arr2_size
) for trailing default-constructed class type elements or otherwise special values) to handle arr1_size < arr2_size
Is there anything simpler, preferably provided by boost that I've missed?
Here is the Boost code you want to bypass, specifically this test is insufficient:
if(static_cast<std::size_t>(count) > current_count)
boost::serialization::throw_exception(
archive::archive_exception(
boost::archive::archive_exception::array_size_too_short
)
);
One workaround is to substitute your own serialization for std::array
. This is easiest if you can avoid including the header boost/serialization/array.hpp
for any translation unit that you serialize std::array
. It is still possible if you need that header file (e.g. to serialize ordinary arrays) - the trick to avoid matching the Boost templated function:
template <class Archive, class T, std::size_t N>
void serialize(Archive& ar, std::array<T,N>& a, const unsigned int /* version */)
...
One way to do this is to explicitly specify your element type:
typedef int MyArrayElementType;
namespace std {
template<class Archive, size_t N>
void serialize(Archive& ar, std::array<MyArrayElementType, N>& a, const unsigned int version)
...
Here's an adaptation of your MCVE:
#include <iostream>
#include <sstream>
#include <array>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/split_free.hpp>
#include <boost/serialization/array.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
// Supply your element type here.
typedef int MyArrayElementType;
namespace std {
template<class Archive, size_t N>
void serialize(Archive& ar, std::array<MyArrayElementType, N>& a, const unsigned int version) {
boost::serialization::split_free(ar, a, version);
}
template<class Archive, size_t N>
void save(Archive& ar, const std::array<MyArrayElementType, N>& a, const unsigned int version) {
// Adapted code from oserializer.hpp save_array_type::invoke().
boost::serialization::collection_size_type count(N);
ar << BOOST_SERIALIZATION_NVP(count);
ar << boost::serialization::make_array(static_cast<MyArrayElementType const*>(&a[0]), count);
}
template<class Archive, size_t N>
void load(Archive& ar, std::array<MyArrayElementType, N>& a, const unsigned int version) {
// Adapted code from iserializer.hpp load_array_type::invoke().
boost::serialization::collection_size_type count;
ar >> BOOST_SERIALIZATION_NVP(count);
if(static_cast<std::size_t>(count) != N)
boost::serialization::throw_exception(
std::runtime_error("std::array size mismatch")
);
ar >> boost::serialization::make_array(static_cast<MyArrayElementType*>(&a[0]), count);
}
}
int main()
{
const size_t arr1_size = 3, arr2_size = 4;
std::stringstream ss;
// save
std::array<int, arr1_size> arr1;
boost::archive::text_oarchive oar(ss, boost::archive::no_header);
oar & arr1;
// load
std::array<int, arr2_size> arr2;
boost::archive::text_iarchive iar(ss, boost::archive::no_header);
iar & arr2; // throw on size inequality, please
}
This uses the same array serialization machinery that the built-in serialization does, so it should have exactly the same performance. If you are able to remove boost/serialization/array.hpp
you could change MyArrayElementType
to a template argument instead.