Date Редакция Категория comp Теги Cpp

Столкнулся с этим у 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