Russian Qt Forum

Qt => Вопросы новичков => Тема начата: deMax от Сентябрь 13, 2017, 09:07



Название: Создать вектор по размеру
Отправлено: deMax от Сентябрь 13, 2017, 09:07
Корректно ли данное безумие или есть лучше варианты? Есть сериализация из ini файла, нужно сделать для intptr_t p = &QVector<ZZ> zz; p->resize() зная только размер ZZ.

Код:
struct ZZ{    int a,b,c;};

template <int sizeType> void setSizeVector(intptr_t vec, int size) {
    QVector<std::array<char,sizeType>> *z2 = (QVector<std::array<char,sizeType>>*)vec;
    z2->resize(size);
}

int main(int argc, char *argv[])
{
    QVector<ZZ> z1;
    intptr_t p = (intptr_t)&z1;
    const int size_t = sizeof(ZZ);
    setSizeVector<size_t>(p, 11);
    qDebug()<<z1.size();
    return 0;
}


Название: Re: Создать вектор по размеру
Отправлено: Igors от Сентябрь 13, 2017, 12:20
Есть сериализация из ini файла, нужно сделать для intptr_t p = &QVector<ZZ> zz; p->resize() зная только размер ZZ.
Поверьте - не нужно. Чем быстрее Вы перестанете мудрить и  спокойно, без всяких затей, распишете сериализацию/десериализацию для каждой структуры - тем лучше. Возня с такими автоматами/пулеметами себе дороже.



Название: Re: Создать вектор по размеру
Отправлено: deMax от Сентябрь 13, 2017, 12:55
Поверьте - не нужно. Чем быстрее Вы перестанете мудрить и  спокойно, без всяких затей, распишете сериализацию/десериализацию для каждой структуры - тем лучше. Возня с такими автоматами/пулеметами себе дороже.
В файл сохранить ручками может и не слишком сложно. Хотя мой классик умеет структуры любой вложенности сохранять достаточно просто(еще бы TODO победить, в принципе уже понял как сделать, но пока нет времени и слишком мудрено получиться):

Код:
struct S1: public Serialize {
    int a,b,c;
    S1() { ADDVALUE(a); ADDVALUE(b); ADDVALUE(c); }};

struct S2: public Serialize {
    QVector<S1> ss;
    S2() { ADDVECTOR(S1, ss); }
    void resizeVectorsOnLoad(IniFormat *ini) {
        ss.resize(ini->sizeVectGroup("ss")); }}; // todo remove

main() {
    S2 in, out;
    in.ss.resize(2);
// заполняем in
    in.save("test2.cfg");
    out.load("test2.cfg");
// in == out

Тут еще преимущество в том что при наличие данных о структуре, я связываю форму со структурой (на каждый тип по строчке, как правило тип один bool) называю похоже переменные и поля в форме и они "сами" связываются :)


Название: Re: Создать вектор по размеру
Отправлено: deMax от Октябрь 04, 2017, 12:22
Можно ли создать структуру, чтобы можно было узнать имя класса наследников по указателю на базовую структуру? Структуры POD без QObject.
struct A1: public Base {}
Base *b(new A1);
qDebug() << b->getName(); // "A1"


Название: Re: Создать вектор по размеру
Отправлено: Bepec от Октябрь 04, 2017, 12:40
А в чём проблема?
Пишем в базовой структуре char* name[20], в конструкторе инициализируем именем класса(наследника, или базового класса). И при любом обращении b->name или a->name получаем текущий тип.
PS Или у вас более глубокие планы?


Название: Re: Создать вектор по размеру
Отправлено: deMax от Октябрь 04, 2017, 12:54
А в чём проблема?
А чтобы в конструкторе не писать? Ну или чтоб у каждого наследника конструктор сам создался с такой строчкой name = type_info(this).name(); ?

c++23 что то долго ждать(и то не факт). Вот думаю как над сериализацией надругаться еще, а то моя реализация не совсем красивая(хоть и работает). У каждого объекта есть поле QMap (описание его структуры) а хотелось бы в static вынести(один на все объекты).


Название: Re: Создать вектор по размеру
Отправлено: __Heaven__ от Октябрь 04, 2017, 13:10
http://en.cppreference.com/w/cpp/types/type_info/name


Название: Re: Создать вектор по размеру
Отправлено: __Heaven__ от Октябрь 04, 2017, 13:12
Не понял, зачем нужно узнавать размер ZZ, если его и так знает QVector и resize делает под количество элементов с учётом размера типа.


Название: Re: Создать вектор по размеру
Отправлено: deMax от Октябрь 04, 2017, 14:08
http://en.cppreference.com/w/cpp/types/type_info/name
Спасибо. Перемудрил, хотел вызвать в конструкторе автоматически, хотя это можно вызвать и в сериализаторе.

Не понял, зачем нужно узнавать размер ZZ, если его и так знает QVector и resize делает под количество элементов с учётом размера типа.

struct B{ int a, b; QString s;}
struct A{ QVector<B> b; }a;
void *p = (void*)a.b;

нужно сделать p->resize(size) зная содержимое структуры B {сдвиг 0 int "a", сдвиг 4 int "b", сlвиг 12 QString "s" }, но не имея её определения.


Название: Re: Создать вектор по размеру
Отправлено: Igors от Октябрь 04, 2017, 14:31
А чем плохо по образцу QDataStream? Напр
Код
C++ (Qt)
MyStream stream;
..
stream << theB.a << theB.b << theB.s; // сериализуем объект класса B
...
stream << theA.b;   // сериализуем объект класса A
..
 
Да, придется оформить операторы для вектора - но 1 раз на все типы
Код
C++ (Qt)
template <class T>
MyStream & operator << ( MyStream & stream, const QVector<T> & vec )
{
...
}


Название: Re: Создать вектор по размеру
Отправлено: __Heaven__ от Октябрь 04, 2017, 15:02
нужно сделать p->resize(size) зная содержимое структуры B {сдвиг 0 int "a", сдвиг 4 int "b", сlвиг 12 QString "s" }, но не имея её определения.
Что-то мешает сделать
Код
C++ (Qt)
#include "B.h"
?


Название: Re: Создать вектор по размеру
Отправлено: deMax от Октябрь 04, 2017, 15:23
А чем плохо по образцу QDataStream?
Делал, но для передачи по сети. Для настроек имен нет, соответственно ini файл не забить автоматически, и QWidget объекты не связать(bool <-> QCheckBox, int <-> QLIneEdit...)

Код
C++ (Qt)
#include "B.h"
?
Сериализатор универсальный на несколько проектов, сделан как библиотека.
Допустим включили хеадер, в коде что писать?

Код:
#include "B1.h"
#include "В2.h"
#include "B3.h"

void serialize(void *p, int size) {
...
if        (type_info(p).name()=="2B1") ((QVector<B1>*)p)->resize(size);
else if(type_info(p).name()=="2B2") ((QVector<B2>*)p)->resize(size);
else if(type_info(p).name()=="2B3") ((QVector<B3>*)p)->resize(size);
... }
Сейчас пока реализована виртуальная функция которая вызывается при загрузке из файла:
Код:
virtual void resizeVectors(IniData ini) {
b1.resize(ini.sizeVector("b1");
b2.resize(ini.sizeVector("b2");
b3.resize(ini.sizeVector("b3");
}

И ASSERT в сериализаторе если забуду для какойнибудь структуры строчку написать(размер не совпадет у вектора с нужным значением).


Название: Re: Создать вектор по размеру
Отправлено: Igors от Октябрь 04, 2017, 15:55
Вы как-то "все о своем" (о девичьем  :)) и уловить Вашу мысль очень непросто
А чем плохо по образцу QDataStream?
Делал, но для передачи по сети. Для настроек имен нет, соответственно ini файл не забить автоматически, и QWidget объекты не связать(bool <-> QCheckBox, int <-> QLIneEdit...)
Ну вот в упор не вижу как это связано с моим вопросом  :)

Код:
#include "B1.h"
#include "В2.h"
#include "B3.h"

void serialize(void *p, int size) {
...
if        (type_info(p).name()=="2B1") ((QVector<B1>*)p)->resize(size);
else if(type_info(p).name()=="2B2") ((QVector<B2>*)p)->resize(size);
else if(type_info(p).name()=="2B3") ((QVector<B3>*)p)->resize(size);
... }
Что же Вы так строки сравниваете? И type_info ни с чем разбираться не будет, оно возвращает инфу для того типа что дали (как sizeof), т.е. дали void *, ну для void* и вернет - и все. С тем же успехом можно написать type_info(void *)

Расскажите чего Вы хотите добиться - только плиз БЕЗ всяких подробностей Вашей системы сериализации, которая уже успела вырасти в изрядного монстра :). Т.е. исходная задача - и все. У меня стойкое впечатление что рулите куда-то явно "не туда" (может я и ошибаюсь)


Название: Re: Создать вектор по размеру
Отправлено: ViTech от Октябрь 04, 2017, 16:20
Расскажите чего Вы хотите добиться - только плиз БЕЗ всяких подробностей Вашей системы сериализации, которая уже успела вырасти в изрядного монстра :). Т.е. исходная задача - и все. У меня стойкое впечатление что рулите куда-то явно "не туда" (может я и ошибаюсь)

Что-то это мне напоминает :).

В зависимости ответов на эти вопросы реализация класса кривой, её компонентов, и работа с ними может различаться кардинально.
Ну да, для точного экспертного анализа нужны точные данные - а как же иначе?  Увы, мой жизненный опыт показывает обратное: чем больше наводящих вопросов - тем меньше содержательного.

Неужто не можете ответить на основе тех данных, что уже есть (как обычно, в первом посте)?  ;)


Название: Re: Создать вектор по размеру
Отправлено: ViTech от Октябрь 04, 2017, 17:10
void *p = (void*)a.b;

Такими преобразованиями и с void * в параметрах функций вы убиваете всю информацию о типе в compile-time. Что после этого вы хотите от компилятора? :) Не издевайтесь над ним и он вам поможет.

Код:
void serialize(void *p, int size) {
...
if        (type_info(p).name()=="2B1") ((QVector<B1>*)p)->resize(size);
else if(type_info(p).name()=="2B2") ((QVector<B2>*)p)->resize(size);
else if(type_info(p).name()=="2B3") ((QVector<B3>*)p)->resize(size);
... }

Если функция может работать с "любым типом", попробуйте std::any (http://en.cppreference.com/w/cpp/utility/any), там эта type_info и есть. Только надолго ли пользователей этой библиотеки сериализации хватит, чтобы лестницы из else if(type_info) строить :).


Название: Re: Создать вектор по размеру
Отправлено: deMax от Октябрь 05, 2017, 11:39
Ну вот в упор не вижу как это связано с моим вопросом  :)
QDatastream упаковывает данные в бинарный формат. Нужна информация о именах.
Цитировать
Расскажите чего Вы хотите добиться - только плиз БЕЗ всяких подробностей Вашей системы сериализации, которая уже успела вырасти в изрядного монстра :). Т.е. исходная задача - и все. У меня стойкое впечатление что рулите куда-то явно "не туда" (может я и ошибаюсь)
сериализацию. Желательно попроще, в принципе возможно надо было protobuf использовать.
В моей реализации уже все работает и пользоваться классом удобно, кроме необходимости ручного изменения размера вектора.
как бы сделать function(int size_of_struct, int size, void *p) { (QVector<size_of_struct>*)p->resize(size); }


Название: Re: Создать вектор по размеру
Отправлено: __Heaven__ от Октябрь 05, 2017, 13:05
Вы осознаёте, что с таким вызовом resize происходит вызов конструкторов не совсем того типа (точнее не вызов нужных), под который предназначен контейнер?
Когда-нибудь это повернётся в часы потраченные на отладку.


Название: Re: Создать вектор по размеру
Отправлено: Igors от Октябрь 05, 2017, 13:11
как бы сделать function(int size_of_struct, int size, void *p) { (QVector<size_of_struct>*)p->resize(size); }
Если возникает необходимость в таком (грязном) хаке - значит что-то не так. И надо думать не о том как "дохакать", а о том как сделать правильно, естественно


Название: Re: Создать вектор по размеру
Отправлено: deMax от Октябрь 05, 2017, 14:32
Вы осознаёте, что с таким вызовом resize происходит вызов конструкторов не совсем того типа (точнее не вызов нужных), под который предназначен контейнер?
POD дата, все равно из ini файла все перезатирается.

Если возникает необходимость в таком (грязном) хаке - значит что-то не так. И надо думать не о том как "дохакать", а о том как сделать правильно, естественно
Ну поэтому я его и не сделал. Виртуальная функция с ручным изменением размера вектора.
А проблема одна, отсутствие в c++ рефлексии. Есть конечно protobuf...


Название: Re: Создать вектор по размеру
Отправлено: ssoft от Октябрь 05, 2017, 17:06
Для организации вменяемой системы сериализации предлагаю посмотреть в сторону boost.

Или можно свести все, например, к такому

Объявление типа
Код
C++ (Qt)
struct SimpleStruct
{
   int m_int;
   double m_double1;
   double m_double2; // например, добавлен при доработке позднее
};
 

Отдельное описание сериализации/десериализации

Код
C++ (Qt)
// перечень версий сериализации (если их требуется вести)
// по умолчанию используется последняя
SERIALIZE_VERSIONS_BEGIN( SimpleStruct )
SERIALIZE_VERSION( Version_1 )
SERIALIZE_VERSION( Version_2 )
SERIALIZE_VERSIONS_END
 
// метод десериализации MyStruct для версии Version_1
// обеспечивает бинарную совместимость с более ранней реализацией
SERIALIZE_LOAD_BEGIN( SimpleStruct, Version_1 )
{
archive
.serialize( value.m_int )
.serialize( value.m_double1 );
}
SERIALIZE_END
 
// метод сериализации/десериализации MyStruct для версии Version_2
// текущий актуальный метод сериализации/десериализации
SERIALIZE_BEGIN( SimpleStruct, Version_2 )
{
archive
.serialize( value.m_int )
.serialize( value.m_double1 )
.serialize( value.m_double2 );
}
SERIALIZE_END
 

Метод сериализации/десериализации единый SERIALIZE_BEGIN .. SERIALIZE_END, но если требуется учесть специфику, то можно использовать взамен пару SERIALIZE_LOAD_BEGIN .. SERIALIZE_END и SERIALIZE_SAVE_BEGIN .. SERIALIZE_END.

А использовать можно так

Код
C++ (Qt)
// Примеры сериализации данных без использования версий
template < typename _Data >
void serializeData ( _Data & data )
{
typedef _Data Data;
// пример десериализации из std::cin
// и сериализации в std::cout
{
typedef ::Serialize::Basic::OStreamArchive< std::ostream > StdOutArchive;
typedef ::Serialize::Basic::IStreamArchive< std::istream > StdInArchive;
Data in_data;
StdInArchive( std::cin )
>> in_data;
StdOutArchive( std::cout )
<< in_data;
}
// пример сериализации в QDebug
{
typedef ::Serialize::Basic::OStreamArchive< QDebug > QDebugArchive;
QDebug stream = qDebug();
QDebugArchive archive( stream );
archive
<< data;
}
// и сериализации в файл с помощью QDataStream
{
typedef ::Serialize::Basic::OStreamArchive< QDataStream > QDataOutArchive;
typedef ::Serialize::Basic::IStreamArchive< QDataStream > QDataInArchive;
QFile file( "test.bin" );
file.open( QFile::WriteOnly );
QDataStream out_stream( &file );
QDataOutArchive out_archive( out_stream );
out_archive
<< data;
file.close();
file.open( QFile::ReadOnly );
QDataStream in_stream( &file );
QDataInArchive in_archive( in_stream );
_Data in_data;
in_archive
>> in_data;
file.close();
}
}
int main ( int, char ** )
{
SimpleStruct my_struct;
serializeData( my_struct );
return 0;
}
 

Реализация пока что проприентарная, полный код выложить не могу, только идеи).


Название: Re: Создать вектор по размеру
Отправлено: Igors от Октябрь 06, 2017, 08:18
Для организации вменяемой системы сериализации предлагаю посмотреть в сторону boost.
Может и так, но перед тем как куда-то смотреть - неплохо бы понять "где проблема". Собсно сериализация - работа "не бей лежачего", проходит любая. Только не нужно впадать в манечку "схлопывания", тупое copy/paste здесь часто оказывается лучшим. Да, может и придется написать сотни (тысячи) строк вместо компактного дустовского кода - зато не будет никаких хитросплетений, "отображений" и.т.п. в которые надо мучительно вникать. Что происходит у ТС мы вряд ли узнаем, но впечатление такое что создана "своя система" c  которой теперь приходится постоянно париться. Да-да, "все работает", но только тут одна  противная мелочь, вот подправить ее - и все! Увы, эти мелочи не кончатся никогда.

И кстати. Не раз (и не 2) я полагал примерно так
Цитировать
Та ладно! Все равно будут только POD типы, ну приведусь, сделаю memmove, sizeof, ничего страшного
И всякий раз получал за это  :)