Russian Qt Forum

Qt => Общие вопросы => Тема начата: Igors от Март 25, 2014, 20:38



Название: QDataStream + exception
Отправлено: Igors от Март 25, 2014, 20:38
Добрый день

Навеяно соседней темой. Желание иметь исключения при любой ошибке чтения/записи вполне естественно - бесконечные проверки быстро утомляют. Но QDataStream ничего не испускает. Как быть?

Спасибо


Название: Re: QDataStream + exception
Отправлено: Old от Март 25, 2014, 21:05
QDataStream это форматировщик, который пишет средствами переданного QIODevice.
Если вы напишите наследника QIODevice, который будет посылать исключения, то все у вас получиться.


Название: Re: QDataStream + exception
Отправлено: Igors от Март 26, 2014, 10:32
QDataStream это форматировщик, который пишет средствами переданного QIODevice.
Если вы напишите наследника QIODevice, который будет посылать исключения, то все у вас получиться.
То ясно но не привлекательно. QDataStream может читать напр из QFile или из QByteArray или еще из чего-то - и все эти классы надо перекрывать  :'(

На первый взгляд может показаться что все просто
Код
C++ (Qt)
struct MyDataStream : public QDataStream {
MyDataStream( QDataStream & strm ) : mStrm(strm) {}
 
template <class T>
MyDataStream & operator >> ( T & dst )
{
mStrm >> dst;
if (mStrm.status() != Ok)
throw "Error";
return *this;
}
 
QDataStream & mStrm;
};
 
Но это не так  :)


Название: Re: QDataStream + exception
Отправлено: Old от Март 26, 2014, 10:34
QDataStream может читать напр из QFile или из QByteArray или еще из чего-то - и все эти классы надо перекрывать  :'(
Нет. Достаточно перекрыть QFile. Вряд ли при чтении из QBuffer (а именно он используется для QByteArray) может произойти ошибка. :)


Название: Re: QDataStream + exception
Отправлено: Old от Март 26, 2014, 10:38
На первый взгляд может показаться что все просто
Но это не так  :)
Ба, да у вы и наследование от QDataStream, и еще в качестве параметра экземпляр передаете... Богатое решение. :)


Название: Re: QDataStream + exception
Отправлено: Igors от Март 26, 2014, 10:42
Нет. Достаточно перекрыть QFile. Вряд ли при чтении из QBuffer (а именно он используется для QByteArray) может произойти ошибка. :)
Пример: рассчитываем что прочитаем 5 чисел - а в файле (или QBuffer) только 2.  

Ба, да у вы и наследование от QDataStream, и еще в качестве параметра экземпляр передаете... Богатое решение. :)
Вот только не совсем верное  :)


Название: Re: QDataStream + exception
Отправлено: Old от Март 26, 2014, 10:44
Вот только не совсем верное  :)
Вы обращаете внимание на такую ерунду?  ::)
Да нормально... сойдет...  ;)


Название: Re: QDataStream + exception
Отправлено: Old от Март 26, 2014, 10:49
Пример: рассчитываем что прочитаем 5 чисел - а в файле (или QBuffer) только 2.  
Вот подумал: можно сделать этакое прокси-устройтсво, которое будет с работать с реальным объектом QIODevice, проверять ошибки и посылать исключения. Такой класс будет один и позволит работать с любыми устройствами.

Еще поправочка:
То ясно но не привлекательно. QDataStream может читать напр из QFile или из QByteArray или еще из чего-то - и все эти классы надо перекрывать  :'(
Я так понимаю, что для вас более привлекательное решение сделать много своих QDataStream, QTextStream, QXmlStream, QJsonStream...


Название: Re: QDataStream + exception
Отправлено: Igors от Март 26, 2014, 11:06
Вот подумал: можно сделать этакое прокси-устройтсво, которое будет с работать с реальным объектом QIODevice, проверять ошибки и посылать исключения. Такой класс будет один и позволит работать с любыми устройствами.
Прошу исполнить  :)


Название: Re: QDataStream + exception
Отправлено: Old от Март 26, 2014, 11:08
Прошу исполнить  :)
Не-не-не, сами-сами. :)


Название: Re: QDataStream + exception
Отправлено: Akon от Март 26, 2014, 18:05
Такое прокси-устройство называется "Декоратор". И в данном случае он не решит всех проблем:
QDataStream::QDataStream ( const QByteArray & a ) -
этот конструктор внутренне создает QBuffer, который вы не сможете декорировать.

Как вариант: сделать свою обертку над QDataStream (она даже не наследник). Функции обертки реализуются через соответствующие функции QDataStream с выбросом исключения при ошибке.


Название: Re: QDataStream + exception
Отправлено: Old от Март 26, 2014, 18:19
Такое прокси-устройство называется "Декоратор".
Я программировал на C++ задолго до того, как начали придумывать названия разным приемам, уж простите старика, я не фапаю на названия паттернов. :)

этот конструктор внутренне создает QBuffer, который вы не сможете декорировать.
И не надо. Если пользователь решил воспользоваться этим конструктором, то он не получит ожидаемые исключения. :)
Тут все просто: ходите получать исключения, используете нужное прокси-устройство, нет - не используете.

Как вариант: сделать свою обертку над QDataStream (она даже не наследник). Функции обертки реализуются через соответствующие функции QDataStream с выбросом исключения при ошибке.
Вот от этого и хотим уйти. Потому что, тогда проще написать свой вариант stream'а с блекжеком и дамами. :)
А в прокси-устройстве будет достаточно перекрыть пару методов для чтения/записи, проверять в них результат и бросать исключения.
Да и логически, это более правильно. Стримы всего лишь форматировщики, умеющие писать/читать в определенном формате, а для самих операций использующие возможности своего QIODevice.
К тому же не нужно будет писать свои обертки для QTextStream, QXmlStreamXXX, QJsonStream и т.д. :)


Название: Re: QDataStream + exception
Отправлено: Igors от Март 26, 2014, 18:26
Такое прокси-устройство называется "Декоратор". И в данном случае он не решит всех проблем:
QDataStream::QDataStream ( const QByteArray & a ) -
этот конструктор внутренне создает QBuffer, который вы не сможете декорировать.
Совершенно верно, при попытке QDataStream::setDevice() он будет удален. Добавлю что это не единственная причина по которой декоратор здесь не проходит

Как вариант: сделать свою обертку над QDataStream (она даже не наследник). Функции обертки реализуются через соответствующие функции QDataStream с выбросом исключения при ошибке.
Ну там их всех точно не перестрелять, а многие просто могут быть просто недоступны. Так что это не выход.


Название: Re: QDataStream + exception
Отправлено: Old от Март 26, 2014, 18:35
Совершенно верно, при попытке QDataStream::setDevice() он будет удален.
Конечно, будет удален. Так же как и с конструктором, вы как пользователь стрима, можете передать указатель на обычное устройство и тогда не будете получать исключения или на специальное прокси устройство и сможете получать. Никаких логических ошибок здесь нет.

Добавлю что это не единственная причина по которой декоратор здесь не проходит
Так огласите пожалуйста весь список. Но что то мне подсказывает, что это все очередные выдумки. :)

И да, декоратор для устройства здесь подходит очень хорошо. Одноразовое написание, простая реализация, весь ранее написанный код остается полностью работоспособным.


Название: Re: QDataStream + exception
Отправлено: Akon от Март 26, 2014, 20:20
Цитировать
И не надо. Если пользователь решил воспользоваться этим конструктором, то он не получит ожидаемые исключения.
Тут все просто: ходите получать исключения, используете нужное прокси-устройство, нет - не используете.
Это плохой подход. Представьте, я получаю в функцию в качестве параметра экземпляр QDataStream. Я не знаю, каким конструктором он был создан, поэтому как мне обрабатывать ошибки: ловить исключениия или проверять инфу об ошибках?

Цитировать
Ну там их всех точно не перестрелять, а многие просто могут быть просто недоступны. Так что это не выход.
Речь идет о пабликах, разумеется. И их не так много. Я в таких случаях поступаю так: реализую сначало то, что непосредственно нужно (возможно, это всего лишь пара функций). В следующем проекте что-то дописывается и так далее.


Название: Re: QDataStream + exception
Отправлено: Old от Март 26, 2014, 20:31
Это плохой подход. Представьте, я получаю в функцию в качестве параметра экземпляр QDataStream. Я не знаю, каким конструктором он был создан, поэтому как мне обрабатывать ошибки: ловить исключениия или проверять инфу об ошибках?
А в вашем случае вы вообще не сможете передать свой стрим в эту функцию, потому что он не является QDataStream.
Плюс можно выкинуть все что могло сериализоваться в QDataStream, оно становится бесполезным.
Я бы это даже решением не назвал.

Как я вижу проблему: есть разработчик, который стоит перед выбором, либо проверять статус на каждый чих, либо использовать исключения. Решает, что с исключениями будет лучше. Тогда он заменяет IO устройство на специальное и оборачивает все в try блок. Все. Никаких других изменений не потребуется.


Название: Re: QDataStream + exception
Отправлено: Igors от Март 27, 2014, 08:53
Речь идет о пабликах, разумеется. И их не так много. Я в таких случаях поступаю так: реализую сначало то, что непосредственно нужно (возможно, это всего лишь пара функций). В следующем проекте что-то дописывается и так далее.
Виноват, не указал сразу: это не проходит по той же причине что и попытка с template выше.

Так огласите пожалуйста весь список. Но что то мне подсказывает, что это все очередные выдумки. :)
А Вы начните писать и через 5 минут узнаете  :)

Эх, была бы лазейка в QDataStream::setStatus - идеально. Но увы  :'(
Хоть "feature request" пиши


Название: Re: QDataStream + exception
Отправлено: Old от Март 27, 2014, 08:54
А Вы начните писать и через 5 минут узнаете  :)
Мне не надо.
Ну вы же уже начали, расскажите. Может вы что не так делаете? :)


Название: Re: QDataStream + exception
Отправлено: Igors от Март 27, 2014, 08:58
Ну вы же уже начали, расскажите. Может вы что не так делаете? :)
Проблема очень типовая, упоминалась и на этом форуме (напр Akon'ом). Поэтому мне, право, неудобно такую бытовуху Вам объяснять  :)


Название: Re: QDataStream + exception
Отправлено: Old от Март 27, 2014, 08:59
Проблема очень типовая, упоминалась и на этом форуме (напр Akon'ом). Поэтому мне, право, неудобно такую бытовуху Вам объяснять  :)
Понятно. Очередное Бла-бла-бла неосилятора. Не интересно.



Название: Re: QDataStream + exception
Отправлено: Igors от Март 27, 2014, 09:09
Понятно. Очередное Бла-бла-бла неосилятора. Не интересно.
А грубить зачем? Я же не виноват что Вы типовых вещей не знаете.


Название: Re: QDataStream + exception
Отправлено: Old от Март 27, 2014, 09:15
А грубить зачем? Я же не виноват что Вы типовых вещей не знаете.
Не придумывайте. :)
Было бы что написать - написали бы.
Если вы не можете что-то реализовать, это не значит, что это реализовать нельзя. У вас много чего не получается. :)
Поэтому, должны страдать. Так и должно быть, это хорошая мотивация учиться писать нормальный код.


Название: Re: QDataStream + exception
Отправлено: Akon от Март 27, 2014, 18:17
Цитировать
А в вашем случае вы вообще не сможете передать свой стрим в эту функцию, потому что он не является QDataStream.
Ну это очевидная конструктивная особенность данного решения, если функция принимает именно QDataStream. Впрочем, если бы использовалось наследование, это ничего бы не дало, поскольку функции QDataStream неполиморфные (поэтому я и отметил необязательность наследования).

Собственно, я имел следующее:
Код:
class Wrapper
{
public:
    explicit Wrapper(DataStream& dataStream) : dataStream_(dataStream) {}
   
    Wrapper& operator<<(qint8 i)
    {
        dataStream << i;
        if (OK != dataStream_.status())
            throw std::runtime_error(getStatusDescription());
    }
    ... and so on

private:
  DataStream& dataStream_;
}

template <typename T>
T& operator<<( T& out, const SerializableObject& obj)
{
    out << obj.name();
    ...
}

Usage:

1.
DataStream stream;
SerializableObject obj;
stream << obj;

2.
DataStream stream;
Wrapper wrapper(stream);
wrapper << obj;  // exception aware



Название: Re: QDataStream + exception
Отправлено: Old от Март 27, 2014, 18:22
Так чем по вашему это решение лучше предложенного мной? :)


Название: Re: QDataStream + exception
Отправлено: Igors от Март 27, 2014, 18:39
Собственно, я имел следующее:
Код:
template <typename T>
T& operator<<( T& out, const SerializableObject& obj)
{
    out << obj.name();
    ...
}
Это совсем уныло т.к. все-все (QVariant, QList, QVector.. огромную массу) придется переписывать с нуля, воспользоваться QDataStream можно только для простых типов  :'(


Название: Re: QDataStream + exception
Отправлено: Akon от Март 27, 2014, 19:19
Цитировать
Так чем по вашему это решение лучше предложенного мной?
Я уже объяснил. В вашем решении поведение QDataStream будет зависеть от того, с помощью какого конструктора он создан. Выбрасывает функция исключение или нет - это часть интерфейса функции. В данном случае эта часть интерфейса вами будет просто-напросто скрыта. Это недопустимо.

Цитировать
Это совсем уныло т.к. все-все (QVariant, QList, QVector.. огромную массу) придется переписывать с нуля, воспользоваться QDataStream можно только для простых типов
Я вас не понимаю. Вот зачем вам лезь в код сериализации QList, например. Вы разработчик этого класса? Разработчиком определен интерфейс (в случае ошибки возвращается пустой список), только им и пользуйтесь. Допустите ситуацию, когда в коде сериализации чужого класса выделяются ресурсы, - своим исключением вы просто будуте давать утечку. Вы должны использовать исключения для ваших классов и не лезть в реализацию чужих.


Название: Re: QDataStream + exception
Отправлено: Old от Март 27, 2014, 19:32
Я уже объяснил. В вашем решении поведение QDataStream будет зависеть от того, с помощью какого конструктора он создан.
Мда. Я чуть выше написал свое виденье проблемы, но повторюсь:

Как я вижу проблему: есть разработчик, который стоит перед выбором, либо проверять статус на каждый чих, либо использовать исключения. Решает, что с исключениями будет лучше. Тогда он заменяет IO устройство на специальное и оборачивает все в try блок. Все. Никаких других изменений не потребуется.

Поправьте меня пожалуйста, может я ее неправильно представляю. Или мы по разному ее представляем.

Да, это он может решать для каждой конкретной функции, в которой будет выполняться чтение/запись. Все инструментальные/вспомогательные функции можно продолжать писать, для стрима без исключений. Исключения можно будет использовать в конкретных сложных функциях, где постоянные проверки состояния, будут путать логику работы.


Выбрасывает функция исключение или нет - это часть интерфейса функции. В данном случае эта часть интерфейса вами будет просто-напросто скрыта. Это недопустимо.
Вы наверное неправильно представляете, что я предлагаю. QDataStream никак модифицироваться не будет и никакой ее интерфейс меняться не будет. Исключения будут приходить от устройства, при невозможности им выполнить запрашиваемую операцию.


Название: Re: QDataStream + exception
Отправлено: Igors от Март 27, 2014, 20:19
Я вас не понимаю. Вот зачем вам лезь в код сериализации QList, например. Вы разработчик этого класса? Разработчиком определен интерфейс (в случае ошибки возвращается пустой список), только им и пользуйтесь. Допустите ситуацию, когда в коде сериализации чужого класса выделяются ресурсы, - своим исключением вы просто будуте давать утечку. Вы должны использовать исключения для ваших классов и не лезть в реализацию чужих.
Так не выходит, напр
Код
C++ (Qt)
 
   Wrapper& operator<<(QList <MyData> & lst)
   {
       dataStream >> lst;
       if (OK != dataStream_.status())
           throw std::runtime_error(getStatusDescription());
   }
 
Допустим файл калечный, записано только 2 эл-та QList из 5. В этом случае третий эл-т будет прочитан, при этом в теле MyData operator >> никаких исключений не возникнет. Только после этого я получу исключение - но поезд может уже уйти. Ну то еще цветочки. А вот хужее
Код
C++ (Qt)
QDataStream & operator >> ( QDataStream & strm, MyClass & dst )
{
return strm >> dst.data1 >> dst.data2 >>...
}
Только после того как вся цепочка отработает может случиться исключение. И то если она не вложена в другую. А объявлять (в операторах) вместо QDataStream свой враппер - смысла/гибкости нет


Название: Re: QDataStream + exception
Отправлено: Akon от Март 27, 2014, 21:27
Ну а что мешает использовать функции сериализации на уровне MyData (и это более правильный дизайн). При чтении 3-го элемента будет выброшено исключение, дальше зависит от конкретной логики.

Цитировать
А объявлять (в операторах) вместо QDataStream свой враппер - смысла/гибкости нет

Дискуссия несколько расфокусировалась. Акцентирую некоторые моменты:
В одном бите нельзя передать 3 значения. Если  вы хотите сохранить QDataStream в интерфейсе функций сериализации, то ни о какой кастомизации речи быть не может, поскольку QDataStream не спроектирован соответствующим образом (нет полиморфных функций). Косвенным образом, вы можете декорировать нижележащий QIODevice, как было предложено Oldом, с уже оговоренной проблемой.

Враппер в данном случае дает такой "полиморфизм" времени компиляции. Да, это не универсальное решение, но универсального решения в даненом случае и не будет.


Название: Re: QDataStream + exception
Отправлено: Old от Март 27, 2014, 23:22
Косвенным образом, вы можете декорировать нижележащий QIODevice, как было предложено Oldом, с уже оговоренной проблемой.
Пока одни борются с ветреными мельницами, у других все работает. :)

Код
C++ (Qt)
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
 
qint8 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0;
 
try
{
QFile file( "test.dat" );
ExProxyDev dev( file );
dev.open( QIODevice::ReadOnly );
 
QDataStream in( &dev );
in >> a >> b >> c >> d >> e >> f;
qDebug() << in.status();
}
catch( std::exception &ex )
{
qDebug() << ex.what();
}
 
qDebug() << a << b << c << d << e << f;
 
return 0;
}
 

Ну не вижу я тут никаких "оговоренных проблем".

Резюмируя: это одно из решение конкретной задачи,  поднятой ТС, которое может применяться для чтения/записи в каких-то исключительных случаях, что-бы не засорять логику постоянными проверками.
Костыль ли это - по мне да, и я никогда бы не использовал его в боевом проекте. Я писал бы свои сериализатор и делал  весь обмен на нем. Но если появилась эта тема, то полноценное решение ТС писать не хочет, а хочет как я понял воспользоваться имеющимися наработками. И для таких случаев лучшего решения я пока не вижу. :)


Название: Re: QDataStream + exception
Отправлено: Akon от Март 28, 2014, 07:24
Цитировать
Пока одни борются с ветреными мельницами, у других все работает.
Хорошо, напишите ваш код для загрузки из QByteArray (вместо QFile) с конструктором QDataStream(const QByteArray& ba).


Название: Re: QDataStream + exception
Отправлено: Old от Март 28, 2014, 07:27
Хорошо, напишите ваш код для загрузки из QByteArray (вместо QFile).
Код
C++ (Qt)
QByteArray data;
QBuffer buf( &data );
ExProxyDev dev( &buf );
 


Название: Re: QDataStream + exception
Отправлено: Old от Март 28, 2014, 07:33
с конструктором QDataStream(const QByteArray& ba).
А зачем мне это делать?
Если пользователь использует этот конструктор, то он намерено и явно отказывается от устройства умеющего посылать исключения.
Именно этот пользователь сейчас принимает решение, через что открывать данные. Ему нужны исключения - одно устройство, нет - другое.

Еще раз. :)
Я не считаю это полноценным решением. Это решение поднятой ТС задачи, который ищет простое решение с минимальными потерями наработок и не хочет писать полноценное решение.


Название: Re: QDataStream + exception
Отправлено: Akon от Март 28, 2014, 08:43
Я предельно понимаю этот вариант. В случае локального использования этого пойдет и будет оптимально с точки зрения кол-ва телодвижений (написания кода). ТС здесь предложены варианты, исходя из своей конкретики он выберет более подходящее.

Мои мысли проистекают из следующего: функции сериализации - это, как правило, паблик интерфейс. Функция принимает на вход DataStream, сконструированный каким-то внешним кодом. Сл-но, в рамках вашего решения этот внешний код также придется считать локальным, поскольку в функции сериализации будет зависимость от того, каким образом создан QDataStream. Как вариант, можно проверять тип девайса из QDataStream в функции сериализации, но это, полагаю, будет совсем некрасиво.


Название: Re: QDataStream + exception
Отправлено: Old от Март 28, 2014, 09:08
Мои мысли проистекают из следующего: функции сериализации - это, как правило, паблик интерфейс. Функция принимает на вход DataStream, сконструированный каким-то внешним кодом. Сл-но, в рамках вашего решения этот внешний код также придется считать локальным, поскольку в функции сериализации будет зависимость от того, каким образом создан QDataStream. Как вариант, можно проверять тип девайса из QDataStream в функции сериализации, но это, полагаю, будет совсем некрасиво.
А для чего функциям сериализации знать в какое устройство они сериализуются?
Код
C++ (Qt)
QDataStream &operator>>( QDataStream &s, MyObject &obj )
{
   s >> obj.data1 >> obj.data2 >> obj.data3;
}
 
Вот типичная функция чтения. С обычным устройством, мы сможем определить ошибку чтения (в лучшем случае) после отработки этого оператора, проверив состояние. В случае с исключениями, мы получим исключение при первой невозможности чтения данных.

Как правило, создание потока и проверка результата происходит на одном уровне. Поэтому, нам ничего не мешает использовать устройство с исключениями и обернуть все в try-блок или использовать проверку статуса в ключевых местах.



Название: Re: QDataStream + exception
Отправлено: Igors от Март 28, 2014, 09:30
Код
C++ (Qt)
QByteArray data;
QBuffer buf( &data );
ExProxyDev dev( &buf );
 
Только ExProxyBufferDev, ExProxyFileDev и.т.д. Да, так можно, о чем упоминалось в начале темы, и этот вариант выглядит самым четким. Но не одно прокси на всех  :)

Еще одно соображение - если QDataStream заменяется наследником, то с его device() не все гладко, если клиент обратится к нему (а он может) то все, хана.

Если  вы хотите сохранить QDataStream в интерфейсе функций сериализации, .
Конечно хочу, зачем мне жесткая зависимость от самопального класса

ТС здесь предложены варианты, исходя из своей конкретики он выберет более подходящее.
Когда мне будет "очень надо" - что-то обсуждать уже времени не будет. Пока мне интересно как это сделать.


Название: Re: QDataStream + exception
Отправлено: Old от Март 28, 2014, 09:34
Только ExProxyBufferDev, ExProxyFileDev и.т.д. Да, так можно, о чем упоминалось в начале темы, и этот вариант выглядит самым четким. Но не одно прокси на всех  :)
Для чего? QBuffer это наследник QIODevice, такой же как и QFile и спокойно может проксироваться одним устройством.


Название: Re: QDataStream + exception
Отправлено: Igors от Март 28, 2014, 09:37
Для чего? QBuffer это наследник QIODevice, такой же как и QFile и спокойно может проксироваться одним устройством.
Нет, в чем Вы можете легко убедиться сами  :)


Название: Re: QDataStream + exception
Отправлено: Old от Март 28, 2014, 09:38
Еще одно соображение - если QDataStream заменяется наследником, то с его device() не все гладко, если клиент обратится к нему (а он может) то все, хана.
С чего это? :)


Название: Re: QDataStream + exception
Отправлено: Old от Март 28, 2014, 09:45
Нет, в чем Вы можете легко убедиться сами  :)
Убеждаюсь. У меня все работает. :)

Код
C++ (Qt)
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
 
qint8 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0;
 
try
{
QFile file( "test.dat" );
if( !file.open( QIODevice::ReadOnly ) )
{
qWarning() << "File not found.";
return 2;
}
QByteArray data = file.readAll();
 
QBuffer buf( &data );
ExProxyDev dev( buf );
dev.open( QIODevice::ReadOnly );
 
QDataStream in( &dev );
in >> a >> b >> c >> d >> e >> f;
qDebug() << in.status();
}
catch( std::exception &ex )
{
qDebug() << ex.what();
}
 
qDebug() << a << b << c << d << e << f;
 
return 0;
}
 


Название: Re: QDataStream + exception
Отправлено: Old от Март 28, 2014, 16:13
А неплохая штука получается. :)

Имеем какой то интерфейс загрузки сложного объекта:
Код
C++ (Qt)
QDataStream &operator>>( QDataStream &s, ObjA &a )
{
   s >> a.m_intVal >> a.m_strVal;
   return s;
}
 
QDataStream &operator>>( QDataStream &s, ObjB &b )
{
   s >> b.m_shortVal >> b.m_listVal;
   return s;
}
 
QDataStream &operator>>( QDataStream &s, ObjBig &big )
{
   s >> big.m_objA >> big.m_objB;
   return s;
}
 
QDataStream &operator>>( QDataStream &s, ObjSuper &super )
{
   s >> super.m_big1 >> super.m_big2 >> super.m_big3;
   return s;
}
 

Теперь, мы может загружать его по старинке:
Код
C++ (Qt)
{
   QList<ObjSuper> objs;
 
   QFile source( ... );
   if( !source.open( ... ) )
   {
         ...
   }
 
   QDataStream s( &source );
   for( int i = 0; i < 100500; ++i )
   {
       ObjSuper tmp;
       s >> tmp;
       if( s.status() )
       {
             // ААаааааа. Ошибка чтения
       }
       objs.append( tmp );
   }
}
 

А можем с исключениями:
Код
C++ (Qt)
{
   QList<ObjSuper> objs;
 
   try
   {
       QFile file( ... );
       ExProxyDev source( file );
       source.open( ... );
 
       QDataStream s( &source );
       for( int i = 0; i < 100500; ++i )
       {
           ObjSuper tmp;
           s >> tmp;
           objs.append( tmp );
       }
   }
   catch( FileError &err )
   {
        qDebug() << err.info();
   }
}
 

* Функции сериализации остаются такими же как и были. Можно сериализовать все Qt-объекты, которые могут работать с QDataStream.
* Чтение/запись завершаются сразу после получения ошибки, а не когда мы доберемся до очередной проверки и решим остановиться (+ можно контролировать точную позицию в файле).
* Минимальные изменения исходников. Меняется, только верхняя функция создающая устройство и проверяющее результат.
* Работать можно с любыми источниками QIODevice.
* Ну и весь функционал в одном классе ExProxyDev.