Читаем Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ полностью

Что следует помнить

• Для простых констант директиве #define следует предпочесть константные объекты и перечисления (enum).

• Вместо имитирующих функции макросов, определенных через #define, лучше применять встроенные функции.

Правило 3: Везде, где только можно используйте const

Замечательное свойство модификатора const состоит в том, что он накладывает определенное семантическое ограничение: данный объект не должен модифицироваться, – и компилятор будет проводить это ограничение в жизнь. const позволяет указать компилятору и программистам, что определенная величина должна оставаться неизменной. Во всех подобных случаях вы должны обозначить это явным образом, призывая себе на помощь компилятор и гарантируя тем самым, что ограничение не будет нарушено.

Ключевое слово const удивительно многосторонне. Вне классов вы можете использовать его для определения констант в глобальной области или в пространстве имен (см. правило 2), а также для статических объектов (внутри файла, функции или блока). Внутри классов допустимо применять его как для статических, так и для нестатических данных-членов. Для указателей можно специфицировать, должен ли быть константным сам указатель, данные, на которые он указывает, либо и то, и другое (или ни то, ни другое):


char greeting[] = “Hello”;

char *p = greeting; // неконстантный указатель,

// неконстантные данные

const char *p = greeting; // неконстантный указатель,

// константные данные

char * const p = greeting; // константный указатель,

// неконстантные данные

const char * const p = greeting; // константный указатель,

// константные данные


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

Когда то, на что указывается, – константа, некоторые программисты ставят const перед идентификатором типа. Другие – после идентификатора типа, но перед звездочкой. Семантической разницы здесь нет, поэтому следующие функции принимают параметр одного и того же типа:


void f1(const Widget *pw); // f1 принимает указатель на

// константный объект Widget

void f1(Widget const *pw); // то же самое делает f2


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

Итераторы STL смоделированы на основе указателей, поэтому iterator ведет себя почти как указатель T*. Объявление const-итератора подобно объявлению const-указателя (то есть записи T* const): итератор не может начать указывать на что-то другое, но то, на что он указывает, может быть модифицировано. Если вы хотите иметь итератор, который указывал бы на нечто, что запрещено модифицировать (то есть STL-аналог указателя const T*), то вам понадобится константный итератор:


std::vectorint vec;

...

const std::vectorint::iterator iter = // iter работает как T* const

vec.begin;

*iter = 10; // Ok, изменяется то, на что

// указывает iter

++iter; // ошибка! iter константный

std::vectorint::const_iterator citer = // citer работает как const T*

vec.begin;

*citer = 10; // ошибка! *citer константный

++citer; // нормально, citer изменяется


Некоторые из наиболее интересных применений const связаны с объявлениями функций. В этом случае const может относиться к возвращаемому функцией значению, к отдельным параметрам, а для функций-членов – еще и к функции в целом.

Если указать в объявлении функции, что она возвращает константное значение, то можно уменьшить количество ошибок в клиентских программах, не снижая уровня безопасности и эффективности. Например, рассмотрим объявление функции operator* для рациональных чисел, введенное в правиле 24:


class Rational {…}

const Rational operator*(const Rational lhs, const Rational rhs);


Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже