Стандарты программирования на С++. 101 правило и рекомендация | страница 78



>   // данного кода)

> }

>};


>Calc с;

>с.Twice("Hello");     // Б: ошибка, функция 3

> // недоступна (могла бы использоваться

> // функция 2, но она не рассматривается, так

> // как у функции 3 лучшее соответствие

> // аргументу)

В строке А обходной путь состоит в том, чтобы явно квалифицировать вызов как >::Twice(21) для того, чтобы заставить поиск имен выбрать глобальную функцию. В строке Б обходной путь состоит в добавлении явного преобразования типа >с.Twiсе(string("Hellо")) для того, чтобы заставить разрешение перегрузки выбрать соответствующую функцию. Некоторые из таких проблем, связанных с вызовами, можно решить и без применения идиомы Pimpl, например, никогда не используя закрытые перегрузки функций-членов, но не для всех проблем, разрешимых при помощи идиомы Pimpl, можно найти такие обходные пути.

Третье следствие влияет на обработку ошибок и безопасность. Рассмотрим пример >Widget Тома Каргилла (Tom Cargill):

>class Widget { // ...

>public:

> Widget& operator=(const Widget&);

>private:

> T1 t1_;

> T2 t2_;

>};

Коротко говоря, мы не можем написать оператор >operator=, который обеспечивает строгую гарантию (или хотя бы базовую гарантию), если операции >T1 или >T2 могут давать необратимые сбои (см. рекомендацию 71). Хорошие новости, однако, состоят в том, что приведенная далее простая трансформация всегда обеспечивает, как минимум, базовую гарантию для безопасного присваивания, и как правило — строгую гарантию, если необходимые операции >T1 и >T2 (а именно — конструкторы и деструкторы) не имеют побочных эффектов. Для этого следует хранить объекты не по значению, а посредством указателей, предпочтительно спрятанными за единственным указателем на реализацию:

>class Widget { // ...

>public:

> Widget& operator=(const Widget&);


>private:

> struct Impl;

> shared_ptr pimpl_;

>};


>Widget& Widget::operator=( const Widget& ) {

> shared_ptr temp(new Impl( /*...*/ ));

> // изменяем temp->t1_ и temp->t2_; если какая-то из

> // операций дает сбой, генерируем исключение, в

> // противном случае - принимаем внесенные изменения:

> pimpl_ = temp;

> return *this;

>}

Исключения

В то время как вы получаете все преимущества дополнительного уровня косвенности, проблема состоит только в увеличении сложности кода (см. рекомендации 6 и 8).

Ссылки

[Coplien92] §5.5 • [Dewhurst03] §8 • [Lakos96] §6.4.2 • [Meyers97] §34 • [Murray93] §3.3 • [Stroustrup94] §2.10, §24.4.2 • [Sutter00] §23, §26-30 • [Sutter02] §18, §22 • [Sutter04] §16-17

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