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



>// управления ресурсом

>bool taxable2 = !((*pi2).isTaxFree()); // доступ к ресурсу

>// через оператор *

>...


Поскольку иногда необходимо получать доступ к ресурсу, управляемому RAII-объектом, то некоторые реализации RAII предоставляют функции для неявного преобразования. Например, рассмотрим следующий класс для работы со шрифтами, инкапсулирующий «родной» интерфейс, написанный на C:


>FontHandle getFont(); // из С API – параметры пропущены

>// для простоты

>void releaseFont(FontHandle fh); // из того же API

>class Font { // класс RAII

>public:

>explicit Font(FontHandle fh) // захватить ресурс:

>:f(fh) // применяется передача по значению,

>{} // потому что того требует C API

>~Font() {releaseFont(f);} // освободить ресурс

>private:

>FontHandle f; // управляемый ресурс – шрифт

>};


Предполагается, что есть обширный программный интерфейс, написанный на C, работающий исключительно в терминах FontHandle. Поэтому часто приходится преобразовывать объекты из типа Font в FontHandle. Класс Font может предоставить функцию явного преобразования, например get:


>class Font {

>public:

>...

>FontHandle get() const {return f;} // функция явного преобразования

>...

>};


К сожалению, пользователю придется вызывать get всякий раз при взаимодействии с API:


>void changeFontSize(FontHandle f, int newSize); // из C API

>Font f(getFont());

>int newFontSize;

>...

>changeFontSize(f.get(), newFontSize); // явное преобразование

>// из Font в FontHandle


Некоторые программисты могут посчитать, что каждый раз выполнять явное преобразование настолько обременительно, что вообще откажутся от применения этого класса. В результате возрастет опасность утечки шрифтов, а именно для того, чтобы предотвратить это, и был разработан класс Font.

Альтернативой может стать предоставление классом Font функции неявного преобразования к FontHandle:


>class Font {

>public:

>...

>operator FontHandle() const // функция неявного преобразования

>{return f;}

>...

>};


Это сделает вызовы C API простыми и естественными:


>Font f(getFont());

>int newSize;

>...

>changeFontSize(f, newFontSize); // неявное преобразование из Font

>// в FontHandle


Увы, у этого решения есть и оборотная сторона: повышается вероятность ошибок. Например, пользователь может нечаянно создать объект FontHandle, имея в виду Font:


>Font f1(getFont());

>...

>FontHandle f2 = f1; // Ошибка! Предполагалось скопировать объект Font,

>// а вместо f1 неявно преобразован в управляемый

>// им FontHandle, который и скопирован в f2


Теперь в программе есть FontHandle, управляемый объектом Font f1, однако он же доступен и напрямую, как f2. Это почти всегда нехорошо. Например, если f1 будет уничтожен, шрифт освобождается, и f2 становится «висячей ссылкой».