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

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

Страниц: 1 [2]   Вниз
  Печать  
Автор Тема: Несколько вопросов от новичка в QT [Решено]  (Прочитано 8120 раз)
Serr500
Гость
« Ответ #15 : Январь 21, 2014, 17:28 »


Немного поразмыслив над смыслом препроцессорных стражей включения хедеров пришел к выводу, что если в iobject.h будет включен objectdispatcher.h, то в результате перед компиляцией глобальная переменная диспетчера по тексту должна быть выше глобальных переменных правил.
Порядок инициализации зависит от порядка в файлах реализации (.c|.cpp), а не в файлах включения (.h|.hxx|.hpp)!

Также хотелось бы до конца разобраться почему система сразу не выдала исключение о не существовании объекта qObjectsDispatcher, а давала возможность вызвать один из его методов.
Потому что он в некотором роде существовал.  Подмигивающий Просто не был до конца инициализирован.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #16 : Январь 21, 2014, 18:04 »

Просмотрев исходники вспомнил, что так и хотел сделать с самого начала, но тогда всплыла проблема cross including-а модулей, и я хедер objectdispatcher.h включил не в iobject.h, а в iobject.cpp. Не знаю почему так произошло, т.к. проблема решается просто. Разобрался с cross including-ом, сейчас вроде все работает как нужно.
По результатам этой работы возникает вопрос о возможных подводных камнях такого решения.
Такое решение как минимум "ненадежно". Напр файл (случайно) был удален из проекта но потом сразу добавлен назад. Или порядок cpp файлов по каким-то др причинам изменился. Или просто др компилятор или даже новая версия - и все, порядок линковки изменился, приплыли.

Простые решения были предложены выше, велосипедить здесь не стоит. Не хотите синглтон (кстати модный, см вику) - соберите все конфликтующие глобалы в одном cpp файле (предназначенном только для этого). Это кстати вполне по-паскалевски. А классы ObjectDispatcher и IObject по-любому друг друга видят
Записан
TsysarAndrew
Гость
« Ответ #17 : Январь 21, 2014, 18:37 »

Потому что он в некотором роде существовал.  Подмигивающий Просто не был до конца инициализирован.
Про это можно что-нибудь почитать? Раньше  в других ЯП с такими ситуациями не сталкивался.
Записан
TsysarAndrew
Гость
« Ответ #18 : Январь 21, 2014, 18:46 »

Проверил, что порядок .cpp  в файле проекта влияет на обсуждаемую ситуацию. Наверно пока сделаю один модуль для всех глобальных объектов. Потом может посмотрю в сторону паттернов.
Записан
Serr500
Гость
« Ответ #19 : Январь 21, 2014, 19:00 »

Потому что он в некотором роде существовал.  Подмигивающий Просто не был до конца инициализирован.
Про это можно что-нибудь почитать? Раньше  в других ЯП с такими ситуациями не сталкивался.
Мнэ-э-э-э... Х.з.  В замешательстве Не помню, где я такое вычитал... Может, у Страуструпа...

Ну, здесь, если мне память не изменяет, логика следующая. Глобальная переменная размещается в стеке, т.е. при запуске программы ей выделяется стековая память. Но выделяется она не так, как хотелось бы - просто резервируется кусок стека для всех глобальных переменных. Точно известно где расположена наша переменная, т.е. её смещение от вершины стека, поэтому мы можем к ней обратиться. Однако, конструктор для переменной ещё не вызван и она находится в неопределённом состоянии. Конструктор будет вызван где-то далее, но до запуска main(). Если другая глобальная переменная пытается при создании обратиться к первой, то мы и получаем ошибку.
Это примерно то же самое, что и обращение к методу/члену класса по нулевому указателю. Иногда такое прокатывает, но чаще всего вызывает ошибку. Упрощённо можно считать, что после выделения памяти до вызова конструктора переменная как бы имеет нулевой (или, если удобнее, "неправильный") указатель.

P.S. Где-то видел вот такую пакость:
Код:
((SomeClass*)NULL)->member();
Записан
TsysarAndrew
Гость
« Ответ #20 : Январь 21, 2014, 19:46 »

Спасибо всем откликнувшимся. Прояснил для себя некоторые вопросы про c++. Тема закрыта.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #21 : Январь 21, 2014, 20:17 »

Ну, здесь, если мне память не изменяет, логика следующая. Глобальная переменная размещается в стеке, т.е. при запуске программы ей выделяется стековая память. Но выделяется она не так, как хотелось бы - просто резервируется кусок стека для всех глобальных переменных. Точно известно где расположена наша переменная, т.е. её смещение от вершины стека, поэтому мы можем к ней обратиться.
Правильно, но только никак не в стеке  Улыбающийся Вообще для глобальных переменных процесс "выделения памяти" отсутствует - один кусок на всех который выделяется ОС'ом при старте приложения. Обращение производится по смещению от начала этого куска, как Вы сказали.

Когда-то по этому поводу почитывал стандарт (небольшое удовольствие, поэтому борзые знатоки любят к нему отсылать Улыбающийся). Там вообще нет термина "глобальная", а есть "non-local variable(s)". Т.е. есть локальные (четко на стеке) - и все остальные. Константы, статики - все это non-local.

Компилятор генерирует ф-ции инициализации для всех глобалов и она выполняется до main. Аналогично ф-ция разрушения после выхода из main. Легко убедиться что идеального порядка инициализации быть не может, напр
Код
C++ (Qt)
class A {
..
globalB.registerA(this);
};
A globalA;
 
class B {
..
globalA.registerB(this);
};
B globalB;
 
« Последнее редактирование: Январь 21, 2014, 20:19 от Igors » Записан
Serr500
Гость
« Ответ #22 : Январь 21, 2014, 21:01 »

Правильно, но только никак не в стеке  Улыбающийся Вообще для глобальных переменных процесс "выделения памяти" отсутствует - один кусок на всех который выделяется ОС'ом при старте приложения.
Стар уже стал, всё позабыл...  В замешательстве Действительно, это не STACK, а DATASEG - сегмент данных приложения.
Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


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