|
Программирование >> Многопоточная библиотека с принципом минимализма
ет оригинальный указатель, передавая объект, на который он ссылался, другому интеллектуальному указателю. В шаблонном классе std: :auto ptr применяется именно этот вид копирования. Опасность этой стратегии очевидна. Неправильное разрушающее копирование может уничтожить данные, профамму и вашу репутацию профаммиста. Эту сфатегию следует применять только в том случае, когда в каждый момент времени на данный объект ссылается только один интеллектуальный указатель. Во время копирования или присваивания одного интеллектуального указателя другому в живых остается только результирующий указатель, а оригинал обнуляется. Ниже показаны консфуктор копирования и оператор присваивания простого класса SmartPtr, демонсфирующие разрушающее копирование. template <class т> class SmartPtr { public: SmartPtrCSmartPtr& src) { pointee = src.pointee ; src.pointee = 0; SmartPtr& operator=CSmartPtr& src) { if (this != fisrc) { delete fiointee ; pointee = stc.pointee ; src.pointee = 0; return *this; По правилам языка С-Ы- в правой части консфуктора копирования и оператора присваивания должна стоять ссылка на константный объект. Классы, реализующие разрушающее копирование, нарушают это правило по очевидным причинам. Поскольку правила языка основаны на резонных соображениях, от их нарушения нельзя ожидать ничего хорошего. Действительно, рассмофим следующий пример. void DisplayCSmartPtr<Something> sp); SmartPtr<Something> spCnew Something); DisplayCsp); Уничтожает объект sp Несмофя на то что функция Display не представляет опасности для своего аргумента (принимая его по значению), она действует как водоворот: все интеллектуальные указатели, попавшие в нее, тонут безвозвратно. После вызова DisplayCsp) указатель sp хранит нулевой адрес. Поскольку интеллектуальные указатели, реализующие стратегию разрушающего копирования, не поддерживают семантику значений, их нельзя хранить в контейнерах и вообще с ними нужно обращаться почти так же осторожно, как и с обычными указателями. Возможность хранить интеллектуальные указатели в контейнере чрезвычайно важна, поскольку контейнеры, состоящие из обычных указателей, очень усложняют ручное управление владением. Однако интеллектуальные указатели, реализующие сфа-тегию разрушающего копирования, для этого не подходят. с другой стороны, интеллектуальные указатели, реализующие стратегию разрушающего копирования, имеют ряд преимуществ. Они почти не тратят дополнительной памяти. Они удобны для передачи владения другому указателю. В этом случае используется эффект водоворота , описанный выще. Они удобны в качестве возвращаемого функцией значения. Если в реализации интеллектуального указателя используется определенный трюк, можно возвращать из функций интеллектуальные указатели с разрушающим копированием. Таким образом, можно быть уверенным, что если в вызывающем модуле возвращаемое значение не используется, оно уничтожается. Они превосходны в качестве переменных стека в функциях, возвращающих значения несколькими способами. Предпринимать меры для уничтожения объекта, на который ссылается интеллектуальный указатель, необязательно - он сам это сделает. Стратегия разрушающего копирования используется в стандартном классе std: :auto ptr. Это создает дополнительное преимущество. Интеллектуальные указатели, обладающие семантикой разрушающего копирования, являются единственным стандартом. Это значит, что многие программисты рано или поздно станут их использовать. По этим причинам реализация класса SmartrPtr должна предусматривать дополнительную поддержку семантики разрушающего копирования. Интеллектуальные указатели используют разные стратегии владения, каждая из которых имеет свои достоинства и недостатки. К наиболее важным приемам относятся глубокое копирование, подсчет ссылок, связывание ссылок и разрушающее копирование. Класс SmartPtr реализует все эти способы в виде стратегии Ownership, позволяя своим пользователям выбирать из них наиболее подходящий. По умолчанию предлагается стратегия подсчета ccbLfioK. 7.6. Оператор взятия адреса Стремясь сделать интеллектуальные указатели максимально похожими на их обычные прототипы, разработчики натолкнулись на незаметный перегружаемый унарный оператор &, или оператор взятия адреса (address-of operator). Программист, реализующий интеллектуальные указатели, может перегрузить этот оператор следующим образом. template <class т> class SmartPtr { public: т** operator&() { return &pointee ; Изобретенный Грегом Колейном (Greg Colvin) и Биллом Гиббонсом (Bill Gibbons) для стандартного интеллектуального указателя std: :auto ptr. Унарный оператор & следует отличать от бинарного оператора &, представляющего собой побитовый оператор AND. Помимо всего прочего, если интеллектуальный указатель должен имитировать обычный указатель, то его адрес можно заменять адресом обычного указателя. В этом случае становится возможной следующая перегрузка оператора, void FunCwidget** pwidget); SmartPtr<widget> spwidgetC...); FunC&spwidget); вызывает оператор * и получает указатель на указатель на объект класса widget На первый взгляд было бы замечательно иметь полную совместимость интеллектуальных и обычных указателей, однако перегрузка унарного оператора & относится к тем остроумным трюкам, которые приносят больще вреда, чем пользы. Есть две причины, по KOTopbnvi перефузка унарного оператора & опасна. Первая заключается в том, что явное определение адреса объекта, на который ссылается интеллектуальный указатель, отнимает возможности автоматического управления владением. Если пользователь имеет свободный доступ к адресу указателя, любая вспомогательная сфукгура, содержащаяся в интеллектуальном указателе, например, счетчик ссылок, становится неработоспособной. Если пользователь непосредственно оперирует адресом обычного указателя, интеллектуальный указатель становится полностью неуправляемым. Вторая причина более прагматична. Дело в том, что перефузка унарного оператора & делает невозможным использование интеллектуального указателя в сочетании с контейнерами из стандартной библиотеки шаблонов STL. Фактически перегрузка унарного оператора & не позволяет применять обобщенное профаммирование, поскольку адрес любого объекта - слищком важное свойство, чтобы так просто с ним обращаться. В большинстве обобщенных кодов предполагается, что применение оператора & к объекту типа т возвращает объект типа Т*. Как видим, оператор взятия адреса представляет собой фундаментальное понятие обобщенного профаммирования. Если им пренебречь, обобщенный код будет вести себя странно как на этапе компиляции, так и (что намного хуже) во время выполнения профаммы. Таким образом, перефужать унарный оператор & для интеллектуальных указателей и вообще для любых объектов не рекомендуется, поэтому в классе SmartPtr унарный оператор & не перефужается. 7.7. Неявное приведение к типам обычных указателей Рассмотрим следующий код. . void Fun(Something* р) SmartPtr(Something> sp(new Something); Fun(sp); Правильно или нет? Скомпилируется этот код или нет? По принципу максимальной совместимости правильный ответ - да . С технической точки зрения сделать приведенный выше код компилируемым очень легко. Для этого достаточно ввести преобразование, определенное пользователем. template <class Т> class SmartPtr {
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |