Определение глобальной константы в C++


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

  1. #define GLOBAL_CONST_VAR 0xFF
  2. int GLOBAL_CONST_VAR = 0xFF;
  3. некоторые функции, возвращающие значение (например,int get_GLOBAL_CONST_VAR())
  4. enum { GLOBAL_CONST_VAR = 0xFF; }
  5. const int GLOBAL_CONST_VAR = 0xFF;
  6. extern const int GLOBAL_CONST_VAR; и в одном исходном файле const int GLOBAL_CONST_VAR = 0xFF;

Вариант (1) - это определенно не тот вариант, который вы хотели бы используйте

Option (2) - Определение экземпляра переменной в каждом объектном файле с помощью заголовочного файла

Вариант (3) - IMO в большинстве случаев заканчивается убийством

Вариант (4) - во многих случаях может быть не очень хорошо, так как перечисление не имеет конкретного типа (C++0X добавит возможность определить тип)

так в большинстве случаев мне нужно выбрать между (5) и (6). Мои вопросы:

  1. что вы предпочитаете (5) или (6)?
  2. почему (5) в порядке, в то время как (2) нет?
9 66
c++

9 ответов:

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

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

// header.hpp
namespace constants
{
    const int GLOBAL_CONST_VAR = 0xFF;
    // ... other related constants

} // namespace constants

// source.cpp - use it
#include <header.hpp>
int value = constants::GLOBAL_CONST_VAR;

(5) "лучше", чем (6), потому что он определяет GLOBAL_CONST_VAR Как интегральное постоянное выражение (ICE) во всех единицах перевода. Например, вы сможете использовать его как размер массива и как метку case во всех единицах перевода. В случае (6) GLOBAL_CONST_VAR будет лед только в той единице перевода, где он определен и только после точки определения. В других переводческих единицах он не будет работать как лед.

Однако имейте в виду, что (5) дает GLOBAL_CONST_VAR внутренняя связь, значение что "адрес идентичности"GLOBAL_CONST_VAR будет разным в каждой единице перевода, т. е. &GLOBAL_CONST_VAR дадут вам другое значение указателя в каждой единице перевода. В большинстве случаев использования это не имеет значения, но если вам понадобится постоянный объект, который имеет согласованную глобальную "адресную идентичность", тогда вам придется пойти с (6), жертвуя льдом константы в этом процессе.

кроме того, когда ЛЕДНОСТЬ константы не является проблемой (не является целочисленным типом) и размер тип становится больше (не скалярный тип), тогда (6) обычно становится лучшим подходом, чем (5).

(2) не в порядке, потому что GLOBAL_CONST_VAR in (2) имеет внешнюю связь по умолчанию. Если вы поместите его в заголовочный файл, вы, как правило, в конечном итоге с несколькими определениями GLOBAL_CONST_VAR, что является ошибкой. const объекты в C++ имеют внутреннюю связь по умолчанию, поэтому (5) работает (и именно поэтому, как я сказал выше, вы получаете отдельный, независимый GLOBAL_CONST_VAR в каждой единице трансляции).

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

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

выбор между 5 и 6 - м; 5 лучше меня.

в 6) значение излишне отделено от его объявления.

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

чтобы ответить на ваш второй вопрос:

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

const int GLOBAL_CONST_VAR = 0xFF;

потому что это постоянный!

Если вы используете C++11 или более поздней версии, попробуйте использовать константы времени компиляции:

constexpr int GLOBAL_CONST_VAR{ 0xff };

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

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

#define GLOBAL_CONST_VAR 0xFF // this is C code not C++
int GLOBAL_CONST_VAR = 0xFF; // it is not constant and maybe not compilled
Some function returing the value (e.g. int get_LOBAL_CONST_VAR()) // maybe but exists better desision
enum { LOBAL_CONST_VAR = 0xFF; } // not needed, endeed, for only one constant (enum elms is a simple int, but with secial enumeration)
const int GLOBAL_CONST_VAR = 0xFF; // it is the best
extern const int GLOBAL_CONST_VAR; //some compiller doesn't understand this