объекты списка и передает исключение в код, вызывавший конструктор. С другой стороны, при присвоении аргумента в теле конструктора такое исключение необходимо обрабатывать с помощью блока 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);
Именно так следует безопасно и эффективно инициализировать переменные-члены. В общем случае всегда, когда это возможно, используйте список инициализации и избегайте инициализации переменных- членов в теле конструктора. Даже если требуется выполнить какие-либо действия с переменными в теле конструктора, список инициализации можно использовать для установки начальных значений, а затем обновить их в теле конструктора.
Рецепт 9.2.
8.2. Использование функции для создания объектов (шаблон фабрики)
Вместо создания объекта в куче с помощью new вам требуется функция (член или самостоятельная), выполняющая создание объекта, тип которого определяется динамически. Такое поведение достигается с помощью шаблона проектирования Abstract Factory (абстрактная фабрика).
Здесь есть две возможности. Вы можете:
• создать функцию, которая создает экземпляр объекта в куче и возвращает указатель на этот объект (или обновляет переданный в нее указатель, записывая в него адрес нового объекта);
• создать функцию, которая создает и возвращает временный объект.
Пример 8.2 показывает оба этих способа. Класс Session
в этом примере может быть любым классом, объекты которого должны не создаваться непосредственно в коде (т.е. с помощью new
), а их создание должно управляться каким-либо другим классом. В этом примере управляющий класс — это SessionFactory
.
#include <iostream>
class Session {};
class SessionFactory {
public:
Session Create();
Session* CreatePtr();
void Create(Session*& p);
// ...
};
// Возвращаем копию объекта в стеке
Session SessionFactory::Create() {
Session s;
return(s);
}
// Возвращаем указатель на объект в куче
Session* SessionFactory::CreatePtr() {
return(new Session());
}
// Обновляем переданный указатель, записывая адрес
// нового объекта
void SessionFactory::Create(Session*& p) {
p = new Session();
}
static SessionFactory f; // Единственный объект фабрики
int main() {
Session* p1;
Session* p2 = new Session();
*p2 = f.Create(); // Просто присваиваем объект, полученный из Create