Являются ли глобальные переменные плохими?

В C/С++ глобальные переменные так же плохи, как считает мой профессор?

Ответ 1

Проблема с глобальными переменными заключается в том, что, поскольку каждая функция имеет к ней доступ, становится все труднее понять, какие функции фактически читают и записывают эти переменные.

Чтобы понять, как работает приложение, вы в значительной степени должны учитывать каждую функцию, которая изменяет глобальное состояние. Это можно сделать, но по мере того, как приложение растет, ему становится все труднее до невозможности (или, по крайней мере, полной траты времени).

Если вы не полагаетесь на глобальные переменные, вы можете передавать состояние между различными функциями по мере необходимости. Таким образом, у вас будет гораздо больше шансов понять, что делает каждая функция, так как вам не нужно учитывать глобальное состояние.

Ответ 2

Важно помнить общую цель: ясность

Правило "нет глобальных переменных" существует, потому что большую часть времени глобальные переменные делают код менее понятным.

Однако, как и многие правила, люди помнят правило, а не то, что предназначалось правилу.

Я видел программы, которые, похоже, удваивают размер кода, передавая огромное количество параметров только для того, чтобы избежать зла глобальных переменных. В конце концов, использование глобалов сделало бы программу более ясной для тех, кто ее читает. Бездумно придерживаясь слова правила, первоначальный программист не смог реализовать правило.

Итак, да, глобалы часто бывают плохими. Но если вы чувствуете, что в конце концов, цель программиста становится понятнее благодаря использованию глобальных переменных, то идите дальше. Однако помните о ясности, которая автоматически возникает, когда вы вынуждаете кого-то получить доступ ко второму фрагменту кода (глобалы), чтобы понять, как работает первая часть.

Ответ 3

Мой профессор говорил что-то вроде: использование глобальных переменных в порядке, если вы правильно их используете. Я не думаю, что мне когда-либо нравилось правильно их использовать, поэтому я редко использовал их вообще.

Ответ 4

Глобальные переменные должны использоваться только тогда, когда у вас нет альтернативы. И да, это включает в себя Singletons. 90% времени, глобальные переменные вводятся для экономии затрат на прохождение вокруг параметра. И затем происходит многопоточное/модульное тестирование/обслуживание, и у вас есть проблема.

Итак, да, в 90% ситуаций глобальные переменные плохи. Исключения, вероятно, не будут замечены вами в ваши годы колледжа. Единственное исключение, которое я могу придумать с головы, имеет дело с глобально глобальными объектами, такими как таблицы прерываний. Такие вещи, как соединение с БД, кажутся глобальными, но это не так.

Ответ 5

Проблема, которую создают глобальные переменные для программиста, заключается в том, что он расширяет поверхность межкомпонентной связи между различными компонентами, использующими глобальные переменные. Это означает, что по мере увеличения числа компонентов, использующих глобальную переменную, сложность взаимодействий также может увеличиваться. Такое усиленное сцепление, как правило, облегчает внедрение дефектов в систему при внесении изменений, а также затрудняет диагностику и исправление дефектов. Такое усиление связи может также уменьшить количество доступных опций при внесении изменений и может увеличить усилие, требуемое для изменений, поскольку часто необходимо проследить через различные модули, которые также используют глобальную переменную, чтобы определить последствия изменений.

Цель инкапсуляции, которая в основном противоположна использованию глобальных переменных, состоит в том, чтобы уменьшить связь, чтобы сделать понимание и изменение источника более простым, безопасным и более простым для тестирования. Намного проще использовать модульное тестирование, когда глобальные переменные не используются.

Например, если у вас есть простая глобальная целочисленная переменная, которая используется в качестве перечислимого индикатора, который различные компоненты используют в качестве конечного автомата, и вы затем вносите изменения, добавляя новое состояние для нового компонента, вы должны затем проследить все остальные компоненты, чтобы гарантировать, что изменение не повлияет на них. Примером возможной проблемы может быть ситуация, когда инструкция switch для проверки значения глобальной переменной перечисления с операторами case для каждого из текущих значений используется в разных местах, и так получается, что некоторые из switch операторы не имеют регистра default для обработки неожиданного значения для глобального, внезапно у вас возникает неопределенное поведение в отношении приложения.

С другой стороны, использование общей области данных может использоваться для хранения набора глобальных параметров, на которые ссылаются в приложении. Этот подход часто используется во встроенных приложениях с небольшим объемом памяти.

При использовании глобальных переменных в такого рода приложениях обычно ответственность за запись в область данных распределяется на один компонент, а все другие компоненты видят область как const и читают из нее, никогда не записывая в нее. Использование этого подхода ограничивает проблемы, которые могут возникнуть.

Несколько проблем из-за глобальных переменных, которые нужно обойти

Когда источник для глобальной переменной, такой как структура, изменяется, все, что его использует, должно быть перекомпилировано, чтобы все, кто использует переменную, знали свой истинный размер и шаблон памяти.

Если более чем один компонент может изменять глобальную переменную, вы можете столкнуться с проблемами, связанными с несовместимыми данными в глобальной переменной. В многопоточном приложении вам, вероятно, потребуется добавить какую-то блокировку или критическую область, чтобы обеспечить способ, чтобы только один поток за раз мог изменять глобальную переменную, а когда поток изменяет переменную, все изменения завершены и зафиксировано, прежде чем другие потоки смогут запросить переменную или изменить ее.

Отладка многопоточного приложения, использующего глобальную переменную, может быть более сложной задачей. Вы можете столкнуться с условиями гонки, которые могут создавать дефекты, которые трудно воспроизвести. С несколькими компонентами, связывающимися через глобальную переменную, особенно в многопоточном приложении, очень сложно понять, какой компонент изменяет переменную, когда и как она меняет переменную.

Конфликт имен может быть проблемой с использованием глобальных переменных. Локальная переменная, имя которой совпадает с именем глобальной переменной, может скрывать глобальную переменную. Вы также сталкиваетесь с проблемой соглашения об именах при использовании языка программирования C. Обходной путь - разделить систему на подсистемы с глобальными переменными для конкретной подсистемы, которые начинаются с одинаковых первых трех букв (см. это на разрешении коллизий пространства имен в задаче C). C++ предоставляет пространства имен, а с C вы можете обойти это, создавая глобально видимую структуру, членами которой являются различные элементы данных и указатели на данные и функции, которые представлены в файле как статические, следовательно, с видимостью файла только для того, чтобы они могли быть только ссылка через глобально видимую структуру.

В некоторых случаях исходное намерение приложения изменяется так, что глобальные переменные, которые предоставляли состояние для одного потока, модифицируются, чтобы позволить запускаться нескольким дублирующимся потокам. Примером может служить простое приложение, предназначенное для одного пользователя, использующее глобальные переменные для состояния, а затем из управления поступает запрос на добавление интерфейса REST, чтобы позволить удаленным приложениям выступать в качестве виртуальных пользователей. Так что теперь вы столкнулись с необходимостью дублировать глобальные переменные и их информацию о состоянии, чтобы у отдельного пользователя, а также у каждого виртуального пользователя из удаленных приложений был свой собственный уникальный набор глобальных переменных.

Использование C++ namespace и метода struct для C

Для языка программирования C++ директива namespace является огромной помощью в уменьшении вероятности столкновения имен. namespace вместе с class и различными ключевыми словами доступа (private, protected и public) предоставляют большинство инструментов, необходимых для инкапсуляции переменных. Однако язык программирования C не предоставляет эту директиву. Эта публикация о потоке стека, Пространства имен в C, предоставляет некоторые методы для C.

Полезный метод состоит в том, чтобы иметь единственную область резидентных данных в памяти, которая определена как struct, которая имеет глобальную видимость, и в этом struct есть указатели на различные глобальные переменные и функции, которые предоставляются. Фактические определения глобальных переменных задаются областью файла с использованием ключевого слова static. Если затем вы используете ключевое слово const, чтобы указать, какие из них доступны только для чтения, компилятор может помочь вам обеспечить доступ только для чтения.

Использование метода struct также может инкапсулировать глобальное, так что оно становится своего рода пакетом или компонентом, который оказывается глобальным. При наличии такого компонента становится проще управлять изменениями, которые влияют на глобальные и функциональные возможности, используя глобальные.

Однако хотя методика namespace или struct может помочь в управлении конфликтами имен, основные проблемы межкомпонентного взаимодействия, которые использование глобалов создает, особенно в современном многопоточном приложении, все еще существуют.

Ответ 6

Да, но вы не берете на себя стоимость глобальных переменных, пока не перестанете работать в коде, который использует глобальные переменные, и начните писать что-то еще, использующее код, который использует глобальные переменные. Но стоимость все еще есть.

Другими словами, это долгосрочная косвенная стоимость, и поэтому большинство людей думают, что это не так.

Ответ 7

Глобальные переменные так же плохи, как вы их делаете, не менее.

Если вы создаете полностью инкапсулированную программу, вы можете использовать глобальные переменные. Это "грех" для использования глобалов, но программирование грехов является довольно философским.

Если вы посмотрите L.in.oleum, вы увидите язык, переменные которого являются исключительно глобальными. Это невозможно, потому что у библиотек нет выбора, кроме как использовать глобальные переменные.

Тем не менее, если у вас есть выбор, и вы можете игнорировать философию программистов, глобальные переменные не так уж плохи.

Также нет Gotos, если вы используете их правильно.

Большая "плохая" проблема заключается в том, что если вы используете их неправильно, люди кричат, высаживается марс, и мир взрывается.... или что-то в этом роде.

Ответ 8

Я бы ответил на этот вопрос другим вопросом: используете ли вы singeltons/Непоняты ли синглтоны?

Потому что (почти все) использование singelton - это прославленная глобальная переменная.

Ответ 9

Если это возможно, ваш код будет подвергнут интенсивному анализу во время судебного разбирательства Верховного суда, то вы хотите избежать глобальных переменных.

Смотрите эту статью: Buggy breathalyzer code отражает важность обзора источника

Были проблемы с стиль кода, который был идентифицирован по обоим исследованиям. Один из стилистических вопросы, касающиеся рецензентов было широкое использование незащищенных глобальные переменные. Это считается плохая форма, поскольку она увеличивает риск, что состояние программы будет становятся непоследовательными или что ценности будут непреднамеренно изменены или перезаписаны. Исследователи также выразили некоторую обеспокоенность по поводу факта что десятичная точность не поддерживаются последовательно на протяжении всей код.

Человек, я уверен, эти разработчики желают, чтобы они не использовали глобальные переменные!

Ответ 10

Проблема в том, что они плохие, и более того, что они опасны. У них есть свой набор плюсов и минусов, и есть ситуации, когда они являются либо самым эффективным, либо единственным способом достижения конкретной задачи. Однако их очень легко использовать, даже если вы предпринимаете шаги, чтобы всегда правильно их использовать.

Несколько профи:

  • Доступ к любой функции.
  • Доступ к ним из нескольких потоков.
  • Никогда не выйдет из области действия до завершения программы.

Несколько минусов:

  • Доступ к любой из функций, без необходимости явно вставляться в качестве параметра и/или документироваться.
  • Небезопасный поток.
  • Загрязняет глобальное пространство имен и потенциально вызывает конфликты имен, если не приняты меры для предотвращения этого.

Обратите внимание, что если вы сделаете так, что первые два плюса и первые два минусы, которые я перечислял, - это то же самое, только с другой формулировкой. Это связано с тем, что функции глобальной переменной действительно могут быть полезны, но те самые функции, которые делают их полезными, являются источником всех их проблем.

Несколько возможных решений некоторых проблем:

  • Подумайте, действительно ли это лучшее или наиболее эффективное решение проблемы. Если есть какие-то лучшие решения, используйте их вместо этого.
  • Поместите их в пространство имен [С++] или singleton struct [C, С++] с уникальным именем (хорошим примером может быть Globals или GlobalVars)) или использовать стандартизованное соглашение об именах для глобальных переменных (например, global_[name] или g_module_varNameStyle (как упоминается underscore_d в комментариях)). Это будет документировать их использование (вы можете найти код, который использует глобальные переменные, путем поиска имени пространства имен/структуры) и минимизировать влияние на глобальное пространство имен.
  • Для любой функции, которая обращается к глобальным переменным, явным образом документирую, какие переменные она читает и которую она пишет. Это облегчит поиск неисправностей.
  • Поместите их в свой исходный файл и объявите их extern в соответствующем заголовке, поэтому их использование может быть ограничено единицами компиляции, которым необходимо получить к ним доступ. Если ваш код опирается на множество глобальных переменных, но каждому модулю компиляции нужен только доступ к нескольким из них, вы можете рассмотреть их сортировку на несколько исходных файлов, поэтому проще ограничить доступ каждого файла к глобальным переменным.
  • Настройте механизм блокировки и разблокировки их и/или создайте свой код, чтобы как можно меньше функций нужно было изменять глобальные переменные. Чтение их намного безопаснее, чем их запись, хотя расписания потоков могут все еще создавать проблемы в многопоточных программах.
  • В принципе, свести к минимуму доступ к ним и максимизировать уникальность имени. Вы хотите избежать конфликтов имен и иметь как можно меньше функций, которые могут потенциально изменить любую данную переменную.

Являются ли они хорошими или плохими, зависит от того, как вы их используете. Большинство склонны использовать их плохо, следовательно, общая осторожность по отношению к ним. Если они используются правильно, они могут стать основным благом; если их использовать плохо, однако они могут и будут возвращаться, чтобы укусить вас, когда и как вы меньше всего этого ожидаете.

Хороший способ взглянуть на это состоит в том, что они сами не плохи, но они дают плохую конструкцию и могут экспоненциально умножать эффекты плохого дизайна.


Даже если вы не собираетесь использовать их, лучше знать, как их безопасно использовать и не использовать, а не использовать их, потому что вы не знаете, как их безопасно использовать. Если вы когда-нибудь окажетесь в ситуации, когда вам нужно сохранить ранее существовавший код, основанный на глобальных переменных, вы можете быть в затруднении, если не знаете, как правильно их использовать.

Ответ 11

Как сказал кто-то (я перефразирую) в другом потоке "Правила вроде этого не должны быть сломаны, пока вы не поймете все последствия этого".

Есть моменты, когда необходимы глобальные переменные или, по крайней мере, очень полезные (например, работа с системными обратными вызовами). С другой стороны, они также очень опасны по всем причинам, о которых вам сказали.

Есть много аспектов программирования, которые, вероятно, должны быть предоставлены экспертам. Иногда вам нужен очень острый нож. Но вы не можете использовать его, пока не будете готовы...

Ответ 12

Глобальные переменные, как правило, плохие, особенно если другие люди работают над одним и тем же кодом и не хотят тратить 20 минут на поиск всех мест, на которые ссылается переменная. И добавление потоков, которые изменяют переменные, приводит к совершенно новому уровню головных болей.

Глобальные константы в анонимном пространстве имен, используемом в одной единице перевода, являются прекрасными и повсеместными в профессиональных приложениях и библиотеках. Но если данные изменяемы и/или должны быть разделены между несколькими TU, вы можете их инкапсулировать - если не ради дизайна, то для кого-либо, отлаживающего или работающего с вашим кодом.

Ответ 13

Использование глобальных переменных - это нечто вроде подметающей грязи под ковриком. Это быстрое решение, и намного проще в краткосрочной перспективе, чем получение пылесборника или вакуума для его очистки. Однако, если вы когда-нибудь закончите перемещать коврик позже, у вас будет большой сюрприз.

Ответ 14

Глобальные переменные являются плохими, если они позволяют вам манипулировать аспектами программы, которые должны быть изменены только локально. В глобальном масштабе ООП часто конфликтуют с идеей инкапсуляции.

Ответ 15

Я думаю, что ваш профессор пытается остановить плохую привычку, прежде чем она начнется.

Глобальные переменные имеют свое место, и, как многие люди говорят, знать, где и когда их использовать, может быть сложно. Поэтому я думаю, вместо того, чтобы вникать в сумасшедшие проблемы, почему, как, когда и где глобальные переменные ваш профессор решил просто запретить. Кто знает, он может запретить их в будущем.

Ответ 16

Абсолютно нет. Неправильное использование их, хотя... это плохо.

Без малейшего удаления их ради этого просто... бессмысленно. Если вы не знаете преимуществ и недостатков, лучше всего четко следовать и делать, как вас учили/учили, но нет ничего скрытого в глобальных переменных. Когда вы понимаете плюсы и минусы, лучше принимайте собственное решение.

Ответ 17

Глобальные переменные хороши в небольших программах, но ужасны, если они используются одинаково в больших.

Это означает, что вы можете легко привыкнуть к их использованию во время обучения. Это то, к чему пытается защитить ваш профессор.

Когда вы будете более опытными, вам будет легче учиться, когда они будут в порядке.

Ответ 18

Нет, они совсем не плохие. Вам нужно посмотреть (машинный) код, созданный компилятором, чтобы сделать это определение, иногда гораздо хуже использовать локальный, чем глобальный. Также обратите внимание, что статическое действие на локальную переменную в основном делает ее глобальной (и создает другие уродливые проблемы, которые может решить реальный глобальный). "Локальные глобальные перемены" особенно плохи.

Глобалы дают вам чистый контроль над использованием вашей памяти, что гораздо труднее сделать с местными жителями. В наши дни это имеет значение только во встроенных средах, где память довольно ограничена. Что-то, что нужно знать, прежде чем вы предполагаете, что встроенные такие же, как в других средах, и предполагайте, что правила программирования одинаковы по всем направлениям.

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

Если вы будете следовать всем правилам программирования, преподаваемым вам в школе или книгам, ваша карьера программирования будет крайне ограничена. Вы можете выживать и иметь плодотворную карьеру, но ширина и ширина доступных вам сред будут крайне ограниченными. Если вы знаете, как и почему правило существует и может защитить его, это хорошо, если вы только рассуждаете, "потому что мой учитель так сказал", хорошо, что это не так хорошо.

Обратите внимание, что такие темы часто обсуждаются на рабочем месте и будут продолжаться, поскольку компиляторы и процессоры (и языки) развиваются, поэтому делают такие правила и не защищают вашу позицию и, возможно, учат урок кем-то с другим мнение, что вы не будете двигаться вперед.

В то же время, тогда просто сделайте то, что говорит самый громкий или несет самую большую палочку (до тех пор, пока вы не будете кричать громче и не будете иметь самую большую палку).

Ответ 19

Да, потому что, если вы позволите некомпетентным программистам использовать их (прочитайте 90%, особенно ученых), вы получите более 600 глобальных переменных, распространяемых более чем на 20+ файлов, и проект из 12 000 строк, где 80% функций недействительны, возвращают void, и полностью работают на глобальном уровне.

Быстро становится невозможно понять, что происходит в любой момент, если вы не знаете весь проект.

Ответ 20

Я хотел бы возразить против того, что во всей этой теме делается то, что делает многопоточность труднее или невозможнее. Глобальные переменные являются общим состоянием, но альтернативы глобальным переменным (например, прохождение указателей) также могут делиться состоянием. Проблема многопоточности заключается в том, как правильно использовать общее состояние, а не то, является ли это состояние доступным через глобальную переменную или что-то еще.

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

Предполагаемая надежда, выраженная в этом потоке, заключается в том, что преобразование программы из однопоточного в многопоточное будет проще, если не использовать глобальные переменные наивно. Да, глобалы облегчают стрельбу в ногу, но есть много способов стрелять в себя.

Я не выступаю за глобальные переменные, так как другие точки по-прежнему остаются, моя точка зрения заключается в том, что количество потоков в программе не имеет ничего общего с областью переменных.

Ответ 21

Использование Глобальные переменные действительно зависит от требований. Его преимуществом является то, что он уменьшает накладные расходы при повторном переходе значений.

Но ваш профессор прав, потому что он поднимает проблемы безопасности, поэтому следует избегать использования глобальных переменных. Глобальные переменные также создают проблемы, которые иногда трудно отлаживать.

Например: -

Ситуации, когда значения переменных становятся изменены в время выполнения. В этот момент трудно определить, какая часть кода модифицирует его и на каких условиях.

Ответ 22

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

Почти всегда лучше не иметь глобальных переменных. Просто напишите настройки дат и установите методы, и приложите их к вам, когда вам понадобятся день, неделя или месяц.

Ответ 23

Я обычно использую глобальные переменные для значений, которые редко меняются, как синглтоны или указатели на функции в динамически загружаемой библиотеке. Использование измененных глобальных переменных в многопоточных приложениях обычно приводит к затруднению отслеживания ошибок, поэтому я стараюсь избегать этого как общего правила.

Использование глобального вместо передачи аргумента часто происходит быстрее, но если вы пишете многопоточное приложение, которое вы часто делаете в настоящее время, оно, как правило, не работает очень хорошо (вы можете использовать thread-statics, но затем увеличить производительность является сомнительным).

Ответ 24

В конце дня ваша программа или приложение могут по-прежнему работать, но это вопрос аккуратности и полного понимания того, что происходит. Если вы разделяете переменное значение среди всех функций, может возникнуть трудность отслеживать, какая функция меняет значение (если функция делает это), и делает отладку в миллион раз сложнее

Ответ 25

В веб-приложениях внутри предприятия можно использовать для хранения данных сеанса/окна/потока/пользователя на сервере по соображениям оптимизации и для предотвращения потери работы, когда соединение неустойчиво. Как уже упоминалось, условия гонки должны быть обработаны. Для этой информации мы используем один экземпляр класса и тщательно управляем.

Ответ 26

Глобальный хороши, когда дело доходит до конфигурации . Когда мы хотим, чтобы наша конфигурация/изменения имела глобальное влияние на весь проект.

Таким образом, мы можем изменить одну конфигурацию, а изменения направлены на весь проект. Но я должен предупредить, что вы должны быть очень умны, чтобы использовать глобальные переменные.

Ответ 27

безопасность меньше означает, что любой может манипулировать переменными, если они объявлены глобальными, так как это объясняет этот пример, если у вас есть баланс как глобальная переменная в вашей банковской программе, пользовательская функция может манипулировать этим, а также сотрудником банка также может манипулировать этим, поэтому возникает проблема. Пользователю следует предоставить только функцию чтения и снятия, но клерк банка может добавить сумму, когда пользователь лично дает наличные деньги в столе. Это так, как это работает.

Ответ 28

В многопоточном приложении вместо глобальных переменных используйте локальные переменные, чтобы избежать состояния гонки.

Условие гонки возникает, когда несколько потоков обращаются к общему ресурсу, причем по меньшей мере один поток имеет доступ на запись к данным. Тогда результат программы не предсказуем и зависит от порядка доступа к данным по различным потокам.

Подробнее об этом здесь https://software.intel.com/en-us/articles/use-intel-parallel-inspector-to-find-race-conditions-in-openmp-based-multithreaded-code