Private-Bookers
C++. Сборник рецептов
вернуться

Когсуэлл Джефф

Шрифт:

Простейшими объектами инициализации являются встроенные типы. Работать с

int
,
char
и указателями очень просто. Рассмотрим простой класс и его конструктор по умолчанию.

class Foo {

public:

 Foo : counter_(0), str_(NULL) {}

 Foo(int c, string* p) : counter_(c), str_(p) {}

private:

 int counter_;

 string* str_;

};

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

Члены инициализируются в порядке их указания в объявлении класса, а не в порядке объявления их в списке инициализации.

Используя тот же класс

Foo
, как и в примере 8.1, рассмотрим переменную-член класса.

class Foo {

public:

 Foo : counter_(0), str_(NULL), cls_(0) {}

 Foo(int с, string* p) :

counter_(c), str_(p), cls_(0) {}

private:

 int counter_;

 string* str_;

 SomeClass cls_;

};

В конструкторе по умолчанию

Foo
инициализировать
cls_
не требуется, так как будет вызван ее конструктор по умолчанию. Но если требуется создать
Foo
с аргументами, то следует добавить аргумент в список инициализации, как это сделано выше, а не делать присвоение в теле конструктора. Используя список инициализации, вы избежите дополнительного шага создания
cls_
(так как при присвоении
cls_
значения в теле конструктора
cls_
вначале создается с использованием конструктора по умолчанию, а затем с помощью оператора присвоения выполняется присвоение нового значения), а также получите автоматическую обработку исключений. Если объект создается в списке инициализации и этот объект в процессе его создания выбрасывает исключение, то среда выполнения удаляет все ранее созданные объекты списка и передает исключение в код, вызывавший конструктор. С другой стороны, при присвоении аргумента в теле конструктора такое исключение необходимо обрабатывать с помощью блока
try/catch
.

Ссылки более сложны: инициализация переменной-ссылки (и

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

Следующая запись в C++ недопустима.

int& x;

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

int а;

int& x = a;

Это все замечательно, но приводит к возникновению проблемы при создании классов. Предположим, вам требуется переменная-член класса, являющаяся ссылкой, как здесь.

class HasARef {

public:

 int& ref;

};

Большинство компиляторов примет эту запись, но только до тех пор, пока вы не попытаетесь создать экземпляр этого класса, как здесь.

HasARef me;

В этот момент вы получите ошибку. Вот какую ошибку выдаст gcc.

error: structure 'me' with uninitialized reference members

(ошибка: структура 'me' с неинициализированными членами-ссылками)

Вместо этого следует использовать список инициализации.

class HasARef {

public:

 int &ref;

 HasARef(int &aref) : ref(aref) {}

};

Затем при создании экземпляра класса требуется указать переменную, на которую будет ссылаться переменная

ref
, как здесь.

int var;

HasARef me(var);

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

  • Читать дальше
  • 1
  • ...
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • ...

Private-Bookers - русскоязычная библиотека для чтения онлайн. Здесь удобно открывать книги с телефона и ПК, возвращаться к сохраненной странице и держать любимые произведения под рукой. Материалы добавляются пользователями; если считаете, что ваши права нарушены, воспользуйтесь формой обратной связи.

Полезные ссылки

  • Моя полка