C ++ Лучшие практики для констант - PullRequest
22 голосов
/ 10 марта 2012

У меня есть целая куча констант, к которым я хочу получить доступ в разных частях моего кода, но к которым я хочу иметь легкий доступ в целом:

static const bool doX = true;
static const bool doY = false;
static const int maxNumX = 5;

и т. Д.

Итак, я создал файл с именем "constants.h" и вставил их все туда и включил его в любой файл, который должен знать константу.

Проблема в том, что это ужасно длявремя компиляции, так как каждый раз, когда я меняю константу, все файлы, на которые ссылается constants.h, должны быть перестроены.(Кроме того, насколько я понимаю, поскольку они статичны, я генерирую копию doX / doY / maxNumX в коде каждый раз, когда я включаю constants.h в новый .cpp, что приводит к килобайтам потерянного пространства в скомпилированномEXE - есть ли способ увидеть это?).

Итак, я хочу решение.Тот, который не «объявляет константы только в файлах, которые их используют», если это возможно.

Есть предложения?

Ответы [ 6 ]

9 голосов
/ 10 марта 2012

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

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

Наконец, static не являетсянеобходимо, так как по умолчанию const глобальные переменные * C100 static.

8 голосов
/ 11 марта 2012

Я думаю, что ваше базовое предположение неверно.

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

Зачем группировать все константы в один заголовок?Это не имеет смысла.Идея заголовка "global.h" так же плоха, как легко включить каждую отдельную зависимость.

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

class File {
public:
  enum class Mode {
    Read,
    Write,
    Append
  };

  File(std::string const& filename, Mode mode);

  // ...
};

В этом случае вполне естественно, что эти константы живут в том же заголовке, что и класс, с которым они связаны (и даже внутрикласс).

Другая категория констант - это те, которые просто пронизывают все приложение.Например:

enum class Direction {
  Up,
  Down,
  Right,
  Left,
  Forward,
  Backward
};

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

В этом случае создается один заголовочный файл для этого конкретногонабор констант в порядке.

И если вы действительно беспокоитесь о группировании этих файлов:

constants/
  Direction.hpp
  Sandwich.hpp
  State.hpp

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

7 голосов
/ 10 марта 2012

Вы объявляете их как extern в заголовке и определяете их в файле реализации.

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

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

EDIT:

C ++ - простой способ сделать это на самом деле обернуть их в класс:

//constants.h
class Constants
{
public:
   static const bool doX;
   static const bool doY;
   static const int maxNumX;
}

//constants.cpp
const bool Constants::doX = true;
const bool Constants::doY = false;
const int Constants::maxNumX = 5;
3 голосов
/ 10 марта 2012

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

//constants.h
class Constants
{
public:
  static bool doX();
  static bool doY();
  static int maxNumX();
};

//constants.cpp
bool Constants::doX() { return true; }
bool Constants::doY() { return false; }
int Constants::maxNumX() { return 42; }

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

Как и в большинстве случаев, это может быть или не быть лучшим в вашем конкретном случае, но это еще один вариант для рассмотрения.

3 голосов
/ 10 марта 2012

В чем проблема с этим использованием?
Не объявляйте тип static в заголовочном файле, он не делает то, что вы думаете, что он делает.

Когда вы объявляете статический файл заголовка, копия этой переменной создается в каждой Единице перевода (TU) , где вы включаете этот файл заголовка, ТАК каждый TUвидит другую переменную, это противоположно вашему ожиданию иметь глобальный.

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

Good Read:
Как мнеиспользовать extern?

0 голосов
/ 11 марта 2012

Прямой способ заключается в создании неконстантных символов:

const bool doX = true;
const bool doY = false;
const int maxNumX = 5;

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

Конечно, есть разные решения:

  • Используя static const s, (или статические члены класса const), значения можно изменять без перекомпиляции всех ссылочных файлов - но, тем самым, значения хранятся в сегменте данных const, который будет вызываться во время выполнения, а не разрешается при компиляции. Если производительность во время выполнения не представляет проблемы (как и для 90% наиболее типичного кода), то все в порядке.

  • Прямой путь в C ++ - использование класса enums, а не глобальных идентификаторов констант (как отмечалось в моей книге). Это более безопасно и, кроме того, работает так же, как const: символы будут разрешены во время компиляции.

...