Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ | страница 62
Правило 15: Предоставляйте доступ к самим ресурсам из управляющих ими классов
Управляющие ресурсами классы заслуживают всяческих похвал. Это бастион, защищающий от утечек ресурсов, а отсутствие таких утечек – фундаментальное свойство хорошо спроектированных систем. В идеальном мире вы можете положиться на эти классы для любых взаимодействий с ресурсами, не утруждая себя доступом к ним напрямую. Но мир неидеален. Многие программные интерфейсы требуют доступа к ресурсам без посредников. Если вы не планируете отказаться от использования таких интерфейсов (что редко имеет смысл на практике), то должны как-то обойти управляющий объект и работать с самим ресурсом.
Например, в правиле 13 изложена идея применения интеллектуальных указателей вроде auto_ptr или tr1::shared_ptr для хранения результата вызова фабричной функции createInvestment:
>std::tr1::shared_ptr
Предположим, есть функция, которую вы хотите применить при работе с объектами класса Investment:
>int daysHeld(const Investment *pi); // возвращает количество дней
>// хранения инвестиций
Вы хотите вызывать ее так:
>int days = daysHeld(pInv); // ошибка!
но этот код не скомпилируется: функция daysHeld ожидает получить указатель на объект класса Investment, а вы передаете ей объект типа tr1::shared_ptr
Необходимо как-то преобразовать объект RAII-класса (в данном случае tr1::shared_ptr) к типу управляемого им ресурса (то есть Investment*). Есть два основных способа сделать это: неявное и явное преобразование.
И tr1::shared_ptr, и auto_ptr предоставляют функцию-член get для выполнения явного преобразования, то есть возврата (копии) указателя на управляемый объект:
>int days = daysHeld(pInv.get()); // нормально, указатель, хранящийся
>// в pInv, передается daysHeld
Как почти все классы интеллектуальных указателей, tr1::shared_ptr и auto_ptr перегружают операторы разыменования указателей (operator-> и operator*), и это обеспечивает возможность неявного преобразования к типу управляемого указателя:
>class Investment { // корневой класс иерархии
>public: // типов инвестиций
>bool isTaxFree() const;
>...
>};
>Investment *createInvestment(); // фабричная функция
>std::tr1::shared_ptr
>pi1(createInvestment()); // для управления ресурсом
>bool taxable1 = !(pi1->isTaxFree()); // доступ к ресурсу
>// через оператор ->
>...
>std::auto_ptr