Надлежащее использование глобальных константных переменных в C ++? - PullRequest
5 голосов
/ 19 сентября 2011

Я работаю над программой для моего класса CS.Это симуляция деятельности транспортной компании в аэропорту.

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

Существуют определенные заданные постоянные значения, такие какчастота прибытия груза, грузоподъемность самолетов, количество времени, которое требуется работнику для обработки определенных предметов и т. д. (все являются целочисленными значениями).Мне необходимо получить доступ к этим переменным через несколько функций в main.cpp

Казалось бы разумным объявить их над функцией main () как const, эффективно делая их глобальными, напримерconst int kTotalTime = 2000;const int kPlaneCapacity = 25;int main(){//...program code}

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

Вопросы: моя логика ошибочна?Как так?Когда целесообразно использовать глобальные переменные (постоянные или нет)?Если это плохое решение, то как бы вы предложили объявлять постоянные значения только для чтения, такие как эти?

Большое спасибо за потраченное время!

Ответы [ 3 ]

5 голосов
/ 19 сентября 2011

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

Я предполагаю, что у вас есть класс Plane, просто сделайте это:

Plane.h

class Plane{
   static const int kPlaneCapacity;
   //....
}

Plane.cpp

const int Plane::kPlaneCapacity = 25;

Кроме того, позаботься о том, что ты понимаешь под константой. Пи постоянная 10 является константой. Я понимаю, как вы думаете, что вместимость самолета постоянна, но подумайте об этом: что если ваш учитель скажет, что для вашего следующего задания вместимость самолета должна быть 30, а не 25.

5 голосов
/ 19 сентября 2011

Что касается размера и цели вашей программы (насколько я понимаю из вашего описания), это, вероятно, не имеет значения, но, поскольку она имеет образовательный контекст, я бы посоветовал: " сделать это правильно ».

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

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

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

// footype.h
class FooType {
  private:
    static const int fooOption;
};
// bartype.h
class BarType {
  private:
    static const float barOption;
};

Вопрос в том, как это инициализировать. Одним из способов может быть создание config.cpp, которое выглядит следующим образом:

#include "footype.h"
#include "bartype.h"

const int FooType::fooOption = 42;
const float BarType::barOption = 7.4;

Таким образом, у вас есть скрытая информация, и у вас все еще есть все параметры конфигурации в одном месте (config.cpp).

Edit:

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

// footype.h
class FooType {
  private:
    static const int& fooOption;
    static const bool& dumpLevel;
};
// bartype.h
class BarType {
  private:
    static const float& barOption;
    static const bool& dumpLevel;
};

config.cpp:

#include "footype.h"
#include "bartype.h"

static const int opt_foo = 42;
static const float opt_bar = 7.4;
static const bool opt_dumpLevel = false;

const int& FooType::fooOption = opt_foo;
const bool& FooType::dumpLevel = opt_dumpLevel;
const float& BarType::barOption = opt_bar;
const bool& BarType::dumpLevel = opt_dumpLevel;

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

3 голосов
/ 19 сентября 2011

Когда целесообразно использовать глобальные переменные (постоянные или нет)?

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

Вот выдержка из хорошей статьи :

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

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

Проблемы выделения памяти - В некоторых средах есть схемы выделения памяти, которые усложняют распределение глобальных переменных. Это особенно верно в языках, где «конструкторы» имеют побочные эффекты, отличные от распределения (поскольку в этом случае вы можете выразить небезопасные ситуации, когда два глобальных элемента взаимно зависят друг от друга). Кроме того, при динамическом связывании модулей может быть неясно, имеют ли разные библиотеки свои собственные экземпляры глобалов или глобальные глобальные ресурсы являются общими.

Тестирование и ограничение - источник, использующий глобальные переменные, несколько сложнее протестировать, поскольку нельзя легко установить «чистую» среду между запусками. В более общем смысле, источник, который использует глобальные сервисы любого рода, которые явно не предоставлены этому источнику, сложно проверить по той же причине.

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

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