Столкнулся с этим у S. Dewhurst в "C++ Gotchas" (Gotcha 2). Он использует для задания количества элементов массива enum
'ы, а не const
. То есть, делает так:
class Foo
{
public:
enum { n = 10 };
int data[n];
};
а не так:
class Foo
{
public:
static const int n = 10;
int data[n];
};
Почему?
Этому есть как минимум два объяснения.
1. Перечисление представляет собой набор связанных друг с другом констант
Вместо разобщенных констант
class Colors
{
public:
static const int RED = 10;
static const int GREEN=12;
static const int BLUE = 3;
int red[RED];
int green[GREEN];
int blue[BLUE];
};
получаем группу констант, объединенных общей темой
class Colors
{
public:
enum { RED = 10, GREEN = 12, BLUE = 3 };
int red[RED];
int green[GREEN];
int blue[BLUE];
};
2. Перечисление может сэкономить память
Память под перечисление выделяется на этапе компиляции. Размер перечисления из последнего примера будет, скорее всего (это зависит от реализации), равен размеру int
.
Почему так? Потому что enum
'ы появились чтобы заменить собой цепочки #define
'ов, вроде такой:
#define SUCCESS 0
#define LITTLE_ERROR 1
#define BIG_ERROR 2
на:
enum error_t
{
SUCCESS,
LITTLE_ERROR,
BIG_ERROR
};
При использовании #define
'ов вы могли написать так
int error = LITTLE_ERROR;
а могли так
int error = 18;
и компилятор не счел бы это ошибкой.
Использование enum
'ов позволяет подключить проверку диапазона возможных значений переменной. Теперь:
error_t error = LITTLE_ERROR; // правильно
error_t error = 18; // ошибка
Итак, перечисления являются не настоящими переменными, но более безопасной формой макросов #define
, способной хранить ряд связанных данных в удобном для чтения виде (поэтому не имеет смысла вопрос о том, где в памяти расположен тот или иной элемент перечисления, например, LITTLE_ERROR
). Впоследствии, компилятор заменит все вхождения элементов перечисления на фактические числовые значения.
Сколько места занимает перечисление? Стандарт ANSI C (6.7.2.2 Enumeration specifiers) говорит об этом так:
"Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined".
Это можно понимать так, что перечисление:
enum enum_t {
A = 1,
B = 2,
C = 3
};
может иметь размер 1 байт (char
), поскольку значения элементов умещаются в тип char
. А перечисление:
enum enum_t {
A = 1,
B = 2,
C = 3,
D = 400
};
может занимать 2 байта (char
), поскольку значения его элементов в char
не умещаются.
Скорее всего, и в том и в другом случае sizeof(enum_t)
даст 4
. Однако, с помощью опции --short-enums
компилятора GCC можно потребовать использовать для перечисления наименьший из подходящих типов данных.
Комментарии
comments powered by Disqus