Archive operators can throw a boost::archive_exception
object which can be caught by an application program. These exceptions are defined
in the files
archive_exception.hpp
and
basic_xml_archive.hpp.
namespace boost {
namespace archive {
class archive_exception : public std::exception
{
public:
typedef enum {
unregistered_class, // attempt to serialize a pointer of
// an unregistered class
invalid_signature, // first line of archive does not contain
// expected string
unsupported_version, // archive created with library version subsequent
// to this one
pointer_conflict // an attempt has been made to directly serialize
// an object after having already serialized the same
// object through a pointer. Were this permitted,
// the archive load would result in the creation
// of an extraneous object.
incompatible_native_format, // attempt to read native binary format
// on incompatible platform
array_size_too_short, // array being loaded doesn't fit in array allocated
input_stream_error // error on stream input
invalid_class_name, // class name greater than the maximum permitted.
// most likely a corrupted archive or an attempt
// to insert virus via buffer overrun method.
unregistered_cast, // base - derived relationship not registered with
// void_cast_register
unsupported_class_version, // type saved with a version # greater than the
// one used by the program. This indicates that the proggram
// needs to be rebuilt.
multiple_code_instantiation, // code for implementing serialization for some
// type has been instantiated in more than one module.
output_stream_error // error on stream output
} exception_code;
exception_code code;
archive_exception(exception_code c) : code(c) {}
virtual const char *what( ) const throw();
};
class xml_archive_exception : public virtual archive_exception
{
public:
typedef enum {
xml_archive_parsing_error, // archive doesn't contain expected data
xml_archive_tag_mismatch, // start/end tag in archive doesn't match program
xml_archive_tag_name_error // tag name contains invalid characters
} exception_code;
xml_archive_exception(exception_code c){}
virtual const char *what( ) const throw();
};
} // archive
} // boost
Была предпринята попытка сериализовать полиморфный класс через указатель, не регистрируя его и не связывая с экспортным ключом. Это также может произойти при использовании нового архива, имя класса которого не было добавлено в систему с макросом<BOOST_ARCHIVE_CUSTOM_ARCHIVE_TYPES>.
Архивы инициируются известной строкой. Если эта строка не найдена при открытии архива, предполагается, что этот файл не является действительным архивом и это исключение выбрасывается.
Эта система записывает текущий номер версии библиотеки во все созданные архивы. Обратите внимание, что это никак не связано с количеством версий классов, используемых прикладными программами. Это относится к версии системы сериализации, используемой для создания архива. Будущие версии этой системы сериализации смогут идентифицировать архивы, созданные в рамках предыдущей системы, и соответствующим образом изменять процедуру загрузки. Поэтому будущие усовершенствования этой системы сериализации не должны устаревать какие-либо существующие архивные файлы. Необходимо только увеличить этот номер версии, когда новая система создает архивы, несовместимые с текущим.
Если когда-нибудь случается, что старая программа пытается прочитать новые архивы, формат которых изменился, это исключение бросается.
Была предпринята попытка загрузить класс, версия которого была увеличена с момента написания программы. Предположим, что классу присвоена версия No3 и программа построена и отправлена третьим лицам. Теперь предположим, что определение этого класса было изменено, номер версии был увеличен до 4 и были построены новые архивы. Если кто-то попытается загрузить эти новые архивы с оригинальной программой, это исключение будет брошено.
Чтобы понять, что означает это исключение, рассмотрим следующий сценарий:<
template<class Archive>
void T::save(Archive &ar) const
{
const A * aptr = &a;
ar<< aptr; // save an instance of object of class A through a pointer
...
ar<< a; // save an instance of an object of class A
assert(aptr == &a); // this must be true
}
template<class Archive>
void T::load(Archive &ar)
{
A * aptr;
ar >>aptr; // create and initialize a new instance of class A
...
ar >>a; // restore state of on object of class A
assert(aptr == &a); // this won't be true
}
>Объект сохраняется сначала через указатель, а затем непосредственно. При загрузке обратно в той же последовательности мы сначала создаем новый объект и загружаем в его данные. Затем мы загружаем данные в другой существующий объект. Там, где мы начали с одного объекта во время сохранения, у нас есть два объекта после восстановления. В более реалистичной ситуации найти эту ошибку может быть очень сложно. К счастью, такие ситуации можно обнаружить при создании архива. Когда это происходит, это исключение выбрасывается.
Библиотека в настоящее время поддерживает текст char, широкоугольный текст и нативные двоичные архивные файлы. В начале каждого архива пишется подпись, указывающая тип архива. Это исключение делается при попытке прочесть архив, написанный в другом формате.
Была предпринята попытка прочитать массив, который больше размера массива. Это должно произойти только тогда, когда размер массива в коде уменьшается после того, как архив уже создан.
Ошибка произошла при вводе потока или вводе. Помимо обычных ситуаций, таких как поврежденный или усеченный входной файл, есть несколько менее очевидных, которые иногда происходят.
Это включает в себя попытку прочитать в конце файла. Текстовые файлы нуждаются в завершающем новом строковом символе в конце файла, который добавляется при вызове деструктора архива. Убедитесь, что выходной архив на потоке уничтожен, прежде чем открывать входной архив на том же потоке. То есть вместо того, чтобы использовать что-то вроде:<
std::stringstream ss;
std::vector<V> v;
boost::archive::text_oarchive oa(ss);
oa << v;
boost::archive::text_iarchive ia(ss);
ia >> v;
>используйте<
std::stringstream ss;
std::vector<V> v;
{
boost::archive::text_oarchive oa(ss);
oa << v;
}
{
boost::archive::text_iarchive ia(ss);
ia >> v;
}
>.
Еще один — передача неинициализированных данных. В целом поведение библиотеки сериализации при передаче неинициализированных данных не определено. Если его можно обнаружить, он вызовет утверждение в сборках отладки. В противном случае, в зависимости от типа архива, он может пройти без инцидента или может привести к архиву с неожиданными данными в нем. Это, в свою очередь, может привести к броску этого исключения.
Длина наименования класса превышает максимально допустимую. Наиболее вероятной причиной является поврежденный архив или попытка вставить вирус с помощью метода переполнения буфера.
Для поддержки литья между указателями базовых и производных классов во время выполнения система поддерживает набор законных конверсий. Обычно эта коллекция хранится без каких-либо явных действий со стороны пользователя библиотеки. Однако есть особые случаи, когда это может быть сделано явно и может быть упущено из виду. Это описано вRuntime Casting. Это исключение делается, если делается попытка обратить между двумя указателями, отношения которых не были зарегистрированы
. Это исключение бросается, когда обнаруживается, что сериализация одного и того же типа была осуществлена более одного раза. Это может произойти, когда код сериализации инстанцируется как в основной линии, так и в одной или нескольких DLLS.
XML, генерируемый процессом сериализации, тесно связан со структурой класса C++, отношениями между объектами и спецификациями сериализации. Если они каким-либо образом перестают синхронизироваться, XML может не отображаться для сериализации загрузки, и это исключение может быть отброшено. Это может произойти по одной из следующих причин:
Архив был отредактирован вне системы сериализации. Это может быть возможно, если только данные будут изменены, а атрибуты XML и структура вложений останутся неизменными. Но любое другое редактирование может сделать архив нечитаемым библиотекой сериализации.
Сериализация была изменена, и архив, созданный старым кодом, читается. То есть редактирование не использовалось должным образом для десериализации ранее созданных архивов.
Это исключение будет выброшено, если имя тега содержит недействительные символы. Действительными символами для тега XML являются: буквы верхнего и нижнего регистра, цифры и следующая пунктуация: .(период), _(подчеркнуть), :(колон) и -(дефис).
Статья Serialization - Archive Exceptions раздела может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.