Название: 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. То ясно но не привлекательно. QDataStream может читать напр из QFile или из QByteArray или еще из чего-то - и все эти классы надо перекрывать :'( Если вы напишите наследника QIODevice, который будет посылать исключения, то все у вас получиться. На первый взгляд может показаться что все просто Код Но это не так :) Название: 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::setDevice() он будет удален. Добавлю что это не единственная причина по которой декоратор здесь не проходитQDataStream::QDataStream ( const QByteArray & a ) - этот конструктор внутренне создает QBuffer, который вы не сможете декорировать. Как вариант: сделать свою обертку над 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 Название: Re: QDataStream + exception Отправлено: Old от Март 27, 2014, 18:22 Так чем по вашему это решение лучше предложенного мной? :)
Название: Re: QDataStream + exception Отправлено: Igors от Март 27, 2014, 18:39 Собственно, я имел следующее: Это совсем уныло т.к. все-все (QVariant, QList, QVector.. огромную массу) придется переписывать с нуля, воспользоваться QDataStream можно только для простых типов :'(Код: template <typename T> Название: 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, например. Вы разработчик этого класса? Разработчиком определен интерфейс (в случае ошибки возвращается пустой список), только им и пользуйтесь. Допустите ситуацию, когда в коде сериализации чужого класса выделяются ресурсы, - своим исключением вы просто будуте давать утечку. Вы должны использовать исключения для ваших классов и не лезть в реализацию чужих. Так не выходит, напрКод Допустим файл калечный, записано только 2 эл-та QList из 5. В этом случае третий эл-т будет прочитан, при этом в теле MyData operator >> никаких исключений не возникнет. Только после этого я получу исключение - но поезд может уже уйти. Ну то еще цветочки. А вот хужее Код Только после того как вся цепочка отработает может случиться исключение. И то если она не вложена в другую. А объявлять (в операторах) вместо 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ом, с уже оговоренной проблемой. Пока одни борются с ветреными мельницами, у других все работает. :)Код
Ну не вижу я тут никаких "оговоренных проблем". Резюмируя: это одно из решение конкретной задачи, поднятой ТС, которое может применяться для чтения/записи в каких-то исключительных случаях, что-бы не засорять логику постоянными проверками. Костыль ли это - по мне да, и я никогда бы не использовал его в боевом проекте. Я писал бы свои сериализатор и делал весь обмен на нем. Но если появилась эта тема, то полноценное решение ТС писать не хочет, а хочет как я понял воспользоваться имеющимися наработками. И для таких случаев лучшего решения я пока не вижу. :) Название: Re: QDataStream + exception Отправлено: Akon от Март 28, 2014, 07:24 Цитировать Пока одни борются с ветреными мельницами, у других все работает. Хорошо, напишите ваш код для загрузки из QByteArray (вместо QFile) с конструктором QDataStream(const QByteArray& ba).Название: Re: QDataStream + exception Отправлено: Old от Март 28, 2014, 07:27 Хорошо, напишите ваш код для загрузки из QByteArray (вместо QFile). Код
Название: 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 в функции сериализации, но это, полагаю, будет совсем некрасиво. А для чего функциям сериализации знать в какое устройство они сериализуются?Код Вот типичная функция чтения. С обычным устройством, мы сможем определить ошибку чтения (в лучшем случае) после отработки этого оператора, проверив состояние. В случае с исключениями, мы получим исключение при первой невозможности чтения данных. Как правило, создание потока и проверка результата происходит на одном уровне. Поэтому, нам ничего не мешает использовать устройство с исключениями и обернуть все в try-блок или использовать проверку статуса в ключевых местах. Название: Re: QDataStream + exception Отправлено: Igors от Март 28, 2014, 09:30 Код
Еще одно соображение - если 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 Нет, в чем Вы можете легко убедиться сами :) Убеждаюсь. У меня все работает. :)Код
Название: Re: QDataStream + exception Отправлено: Old от Март 28, 2014, 16:13 А неплохая штука получается. :)
Имеем какой то интерфейс загрузки сложного объекта: Код
Теперь, мы может загружать его по старинке: Код
А можем с исключениями: Код
* Функции сериализации остаются такими же как и были. Можно сериализовать все Qt-объекты, которые могут работать с QDataStream. * Чтение/запись завершаются сразу после получения ошибки, а не когда мы доберемся до очередной проверки и решим остановиться (+ можно контролировать точную позицию в файле). * Минимальные изменения исходников. Меняется, только верхняя функция создающая устройство и проверяющее результат. * Работать можно с любыми источниками QIODevice. * Ну и весь функционал в одном классе ExProxyDev. |