Здравствуйте, Forrest_Gump, Вы писали:
F_G>Собственно вопрос.
F_G>Есть ли такие случаи, когда без глобальных переменных не обойтись ?
Конечно. Собственно говоря, глобальная переменная на новомоязе -- это синглетон. Практически в любом проекте есть объекты, которые по смыслу существуют в одном экземпляре и которые широко используются во всём проекте. Например -- подсистема для ведения log а. А ввод-вывод? cin и cout -- типичные синглетоны. Главное окно в оконном приложении. и.т.п.
Никакого криминала в использовании глобальных переменных нет. Просто не надо увлекаться.
Здравствуйте, Евгений Коробко, Вы писали:
ЕК>Некоторое уточнение: все эти объекты не должны быть глобальными, т.е. не должны быть в global scope. Они должны быть либо в namespace, либо статическим полем класса.
Слово должен здесь не уместно. Можно сказать -- хорошо бы. Правда, в C такое невозможно. А в C++ , да не следует без особой необходимости засорять global scope.
ЕК>Во-вторых, часто разумнее сделать следующее. Вместо глобальной переменной ЕК>int x; ЕК>сделать ЕК>int& get_x() ЕК>{ ЕК> static int x; ЕК> return x; ЕК>}
У этого подхода довольно большие накладные расходы. Во-первых, на вызов функции, во-вторых, если x будет иметь нетривиальный конструктор, то компилятор создаст скрытый флажок, который будет проверяться при каждом вызове функции для того, чтобы определить момент первого вызова и сделать в этом случае вызов конструктора. Это создаёт проблему в многопоточных приложениях.
ЕК>Во-первых, инкапсуляция, а во-вторых, решает проблему с упорядочиванием инициализации глобальных переменных. Дело в том, что если глобальные переменные описаны в разных единицах трансляции, то порядок вызова их конструкторов не определён.
Если вы завернули эти объекты в функции то тоже не определён.
Если вы хотите создать несколько глобальных объектов в определённом порядке, следует поместить определения этих объектов в один файл. Во всяком случае, это лучшее, что можно сделать. А по-хорошему, не стоит создавать зависимостей такого сорта. Если уж очень нужно, то лучше проводить инициализацию объектов в два этапа. Конструктор должен делать минимальную работу, переводя объект в нулевое состояние, а для рабочей инициализации стоит использовать инициализирующий метод. И вызывать эти методы в правильном порядке в начале main. Дополнительный бонус -- можно перехватывать исключения. Бонус два -- можно параметризовать вызовы инициализирующих функций аргументами командной строки, например, или запросив у пользователя параметры.
Здравствуйте, PK Sly, Вы писали:
PS>Это — бред из серии "никогда под страхом смертной казни не используйте goto".
А потом сидишь и копаешься в куче этих глобальных переменых и переходов куда попало Мне как-то пришлось... в чужом коде рыться, вот таком противном.
Глобальные переменные — это ОТСТОЙ!!!
С тех пор, у меня к защитникам глобальных переменных отношение не очень хорошее. Их можно позволить парочку, если очень надо. но я бы запретила многие злоупотребляют этим. Ну да, это ж если что прототип функции надо менять, или новую заводить, а тут завел глобальную и все дела. А потом поди разберись в этой каше.
Jane
Re[2]: Всегда ли глобальные переменные - это плохо ?
Здравствуйте, sluge, Вы писали:
S>я считаю что нет. ну невиноваты глобальные перемнные в том что их менеджеры не любют иногда они очень удобны
Виноваты-виноваты. Глобальные переменные виновны в появлении неявных зависимостей. А менеджеры именно их не любят, т.к. собственно их работа и состоит в управлении зависимостями.
... << RSDN@Home 1.1.4 beta 1 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Всегда ли глобальные переменные - это плохо ?
Некоторое уточнение: все эти объекты не должны быть глобальными, т.е. не должны быть в global scope. Они должны быть либо в namespace, либо статическим полем класса.
Во-вторых, часто разумнее сделать следующее. Вместо глобальной переменной
int x;
сделать
int& get_x()
{
static int x;
return x;
}
Во-первых, инкапсуляция, а во-вторых, решает проблему с упорядочиванием инициализации глобальных переменных. Дело в том, что если глобальные переменные описаны в разных единицах трансляции, то порядок вызова их конструкторов не определён.
Posted via RSDN NNTP Server 1.8 beta
Евгений Коробко
Re: Универсальный способ избавления от глобальных переменных
Здравствуйте, Forrest_Gump, Вы писали:
F_G>Есть ли такие случаи, когда без глобальных переменных не обойтись ?
Есть универсальный очень простой способ избавления от глобальных переменных.
Начнем с простого и всем известного:
Имеем код:
VAR
g: INTEGER;
PROCEDURE DoSmth();
BEGIN
g := 1;
END;
превращаем его в код:
TYPE
TMyType = CLASS
g: INTEGER;
PROCEDURE DoSmth;
END;
PROCEDURE TMyType.DoSmth;
BEGIN
SELF.g := 1;
END;
Спрашивается что мы сделали? Переменная g — была контекстом исполнения процедуры DoSmth. Мы взяли и соединили данные и методы в одно целое — получили то что в рамках ООП называется объектом. Все тривиально.
Следующий шаг: — у нас есть уже не просто процедуры и глобальные переменные, а теперь есть объекты и глобальные переменные. Однако что нам мешает повторить еще раз тот самый первый шаг, но уже на более высоком уровне абстракции? Каждый объект живет в каком-то контексте глобальных переменных. Вот мы берем и объявляем этот контекст глобальных переменных другим объектом — Context (Domain, Document, Environment,...)
TYPE
Context = CLASS
GlobalX: INTEGER;
GlobalY: INTEGER;
GlobalZ: INTEGER;
END;
TMyType = CLASS
FContext: Context
g : INTEGER;
CONSTRUCTOR Create(c: Context);
END;
Если на первом шаге мы соединили вместе данные и процедуры получив объект, то на втором шаге мы соединили объект и его контекст — тоже объект в рамках которого тот первый объект живет. И так можно двигаться дальше: к Context-у присоединить Domain в котором он определен, к Domain-у присоединить Document в рамках которого он существует и т.д. Получается иерархическая структура контекстов существования.
TYPE
Environment = CLASS//...END;
Document = CLASS
FEnvironment: Environment;
//...CONSTRUCTOR Create(e: Environment);
END;
Domain = CLASS
FDocument: Document;
//...CONSTRUCTOR Create(d: Document);
END;
Context = CLASS
FDomain: Domain;
//...CONSTRUCTOR Create(d: Domain);
END;
TMyType = CLASS
FContext: Context
//...CONSTRUCTOR Create(c: Context);
END;
Вот. А начиналось все с того что люди объединили данные и процедуры в одно целое и назвали это объектом. Затем осталось только вкладывать одни объекты внутрь других как матрешки... — и ни одной глобальной переменной больше не нужно.
Здравствуйте, Аноним, Вы писали:
_J_>>Глобальные переменные — это ОТСТОЙ!!!
А>Вот тут как раз я спрашивал про метрики Харрисона и Кукак. А на сколько это отстой т.е на сколько это увеличивает сложность подпрограммы
Если честно я теорией не заморачивалась мне пришлось на практике работать с программой в которой была просто огромная куча глобальных переменных. Сразу оговорюсь — это был чистый C без плюсов.
Очень тяжело.
Многие проблемы, которые при нормальном коде — параметры функций, правильное применение const модификаторов — отслеживались просто по коду, так приходилось дебажить. Много и долго.
Я глянула одним глазом про метрики, похоже они придуманы для функционального программирования. А в ООП ведь есть еще статические члены классов, тоже каким-то боком глобальные А давно эта мера была придумана?
Здравствуйте, Forrest_Gump, Вы писали:
F_G>Собственно вопрос.
F_G>Есть ли такие случаи, когда без глобальных переменных не обойтись ? F_G>Хотелось бы услышать мнение тех, кто имеет опыт разработки более-менее крупных проектов. F_G>Интересно также услышать ответ на вопрос отдельно в контексте C и C++.
Для C++ лучше любыми способами избегать глобальных переменных, особенно для представления сложных типов. Грабли.
Вместо них лучше использовать статические члены класса.
Здравствуйте, Gaperton, Вы писали:
G>Здравствуйте, Forrest_Gump, Вы писали:
F_G>>Собственно вопрос.
F_G>>Есть ли такие случаи, когда без глобальных переменных не обойтись ? F_G>>Хотелось бы услышать мнение тех, кто имеет опыт разработки более-менее крупных проектов. F_G>>Интересно также услышать ответ на вопрос отдельно в контексте C и C++. G>Для C++ лучше любыми способами избегать глобальных переменных, особенно для представления сложных типов. Грабли. G>Вместо них лучше использовать статические члены класса.
У меня сложилось впечатление, что механическая замена глобальных переменных синглтонами способна решить все проблемы связанные с глобальными переменными. Я категорически не разделяю это мнение. Глобальные переменные в первую очередь плохи тем, что они провоцируют появление неявных зависимостей, однако массивное использование синглтонов чревато тем же.