Russian Qt Forum
Ноябрь 25, 2024, 18:22 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Странности с объектом класса  (Прочитано 3214 раз)
joffadark
Гость
« : Март 06, 2015, 01:03 »

Здравствуйте. Возникла непонятная проблема. Код довольно громоздок, т.к. проект немаленький. Поэтому попробую описать словами и маленькими вставками псевдокода.

Есть класс десериализатор (CPacket), который при помощи метода FromBinary заполняет из "двоичных" данных на входе (const char* buf, int len) свои собственные поля.

Есть еще один класс  (CNetworkSession), класс создает объект QUdpSocket, и ловит из него датаграммы.
По факту прихода новой датаграммы CNetwork генерирует сигнал (onNewPacket) и передает туда массив char* и его длину int length.
Т.е если псевдокодом описать:

Код
C++ (Qt)
CNetworkSession::CNetworkSession()
{
 this->udpSocket = new QUdpSocket();
 this->udpSocket->bind(...);
 connect(this->udpSocket, SIGNAL(readyRead()), this, SLOT(NewPacketRecv()));
 ...
}
 
void CNetworkSession::NewPacketRecv()
{
 char* buf = (char*)malloc(...);
 int len  = this->UdpSocket->readDatagram(...);
 if (len > 0)
 {
   buf = (char*)realloc(buf, len);
   emit this->onNewPacket(buf, len);
 }
}

Ну и есть, соответственно, третий класс который уже ловит сигнал onNewPacket(...) от CNetworkSession, применяет класс десериализатор CPacket, ну и в общем далее делает что хочет с этими структурированными данными.

примерно таким образом:
Код
C++ (Qt)
void CEndpointClass::SlotOnNewPacket(char* buf, int len)
{
   CPacket packet;
   packet.FromBinary(buf, len);
 
   int someValue = packet.getSomeValue();    // <----- trouble
}

В общем, когда вызывается packet.FromBinary() внутри него все данные десериализуются правильно (трассировка + watch показали).

когда далее в someValue происходит присвоение packet.getSomeValue(), в someValue попадают абсолютно неверные данные.

если идти трассировкой в слоте SlotOnNewPacket и посмотреть в Watch значения объекта packet какбы из слота, то там тоже неверные данные. Причем они такие, как будто в структуре класса произошло некое смещение.
Если унаследовать CPacket от QObject и добавить к нему макрос Q_OBJECT, при трассировке из слота в объекте поля становятся верными.
но в intSomeValue всё равно попадает какая-то фигня.
getSomeValue() - это обычный геттер приватного свойства.

Подскажите пожалуйста, что за магия такая Грустный

Самое фиговое, что всё это выполняется в одном трэде и не распараллеливалось (да и не нужно). Я бы понял, если бы что-то подобное творилось между разными тредами.

Прям расстраивает Qt во времена таких диких странностей.
Записан
Alex Custov
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2063


Просмотр профиля
« Ответ #1 : Март 06, 2015, 01:13 »

когда далее в someValue происходит присвоение packet.getSomeValue(), в someValue попадают абсолютно неверные данные.

Десериализатор работает неправильно, это же очевидно. Минимальный код в студию, И минимальный набор бинарных данных в аттаче.

Прям расстраивает Qt во времена таких диких странностей.

Шутку оценил Смеющийся
Записан
joffadark
Гость
« Ответ #2 : Март 06, 2015, 08:57 »

когда далее в someValue происходит присвоение packet.getSomeValue(), в someValue попадают абсолютно неверные данные.

Десериализатор работает неправильно, это же очевидно. Минимальный код в студию, И минимальный набор бинарных данных в аттаче.

Прям расстраивает Qt во времена таких диких странностей.

Шутку оценил Смеющийся

Ну, во-первых, это действительно шутка Улыбающийся

А по поводу десериализации я же написал, что внутри FromBinary все свойства объекта класса CPacket устанавливаются верно (Wireshark + я знаю, что должно быть). Возможно как-то некорректно описал.
Т.е. методика отладки такова:

Код
C++ (Qt)
void CEndpointClass::SlotOnNewPacket(char* buf, int len)
{
   CPacket packet;
   packet.FromBinary(buf, len); // <-- brake point, trace so vhodom. Vse svoystva objecta zapolnyautsa verno.
 
   // Srazu posle vozvrata iz FromBinary, watch pokazivaet uzhe sovsem drugie znachenia svoystv objecta.
 
   int someValue = packet.getSomeValue(); // tut v someValue popadaet znachenie tozhe nevernoe, ono dazhe ne sootvetstvuet nevernomu znacheniy watch.
 
}

Если же CPacket сделать наследником QObject и добавить ему макрос Q_OBJECT, то сразу при выходе из FromBinary watch показывает ВЕРНЫЕ значения свойств объекта. но в int someValue = packet.getSomeValue(); падает НЕВЕРНОЕ ЗНАЧЕНИЕ.

Примерное краткое описание CPacket, без наследдования от QObject:
Код
C++ (Qt)
class CPacket
{
public:
 CPacket();
 ~CPacket();
 int getSomeValue() { return this->someValue; }
 ... // drugie getteri
 void FromBinary(char* buf, int len);
private:
 int someValue;
 ... // drugie private svoystva
}

Соответственно, c наследованием от QObject:
Код
C++ (Qt)
class CPacket : public QObject
{
   Q_OBJECT
public:
 CPacket();
 ~CPacket();
 int getSomeValue() { return this->someValue; }
 ... // drugie getteri
 void FromBinary(char* buf, int len);
private:
 int someValue;
 ... // drugie private svoystva
}

после добавления наследования очистку, Qmake и пересборку делал.

P.S. забыл сказать, что ОС Ubuntu Linux 12.04 LTS. + статическая сборка Qt 5.3.1
« Последнее редактирование: Март 06, 2015, 09:03 от joffadark » Записан
Alex Custov
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2063


Просмотр профиля
« Ответ #3 : Март 06, 2015, 10:54 »

А по поводу десериализации я же написал, что внутри FromBinary все свойства объекта класса CPacket устанавливаются верно (Wireshark + я знаю, что должно быть). Возможно как-то некорректно описал.
Т.е. методика отладки такова:

Это всё гадание на кофейной гуще. Нужно сократить рабочий пример до чтения заранее подготовленных бинарных данных из файла и их десериализации. Если проблема всё ещё воспроизводится - выложить этот код и данные.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Март 06, 2015, 11:01 »

Попробуйте печатать "адрес + значение переменной" в 2 местах (знаете в каких)
Записан
joffadark
Гость
« Ответ #5 : Март 07, 2015, 22:40 »

Спасибо всем!  Смеющийся
Проблему нашел, когда - по совету Alex и Igors - не поленился и запилил полный прототип
механизма (он не совсем прост, чтобы просто его воспроизвести в демо проекте, пришлось потратить субботний вечер за пивом). В процессе запила понял, что дико всё накостылил и, упростив код, решил проблему.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #6 : Март 07, 2015, 23:15 »

Юнит тесты спасут капитана!
Записан

ArchLinux x86_64 / Win10 64 bit
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.408 секунд. Запросов: 23.