C++: библиотека программиста



Download 1,95 Mb.
Pdf ko'rish
bet49/144
Sana24.02.2022
Hajmi1,95 Mb.
#223123
TuriРеферат
1   ...   45   46   47   48   49   50   51   52   ...   144
Bog'liq
C -Eldjer-Djeff-for-Real-Programmers-RUS-www.itlibitum.ru

 
75 
Умные указатели как идиома 
Возникающие проблемы стоит разбирать последовательно. До арифметических операций с 
указателями мы доберемся позже, поэтому пока будем пользоваться 
ptr_diff

Оператор -> 
Теперь вы знаете, почему оператор 
->
был сделан перегружаемым. В полном соответствии с 
синтаксисом, описанным в главе 2, 
PFoo
теперь обзаводится собственным оператором 
->
. Оператора 
преобразования хватает для вызова внешних функций. Приведенный ниже вызов функции 
f()
работает, потому что у компилятора хватает ума поискать оператор преобразования, соответствующий 
сигнатуре функции, и в данном случае оператор 
Foo*()
прекрасно подходит. 
class PFoo { 
private: 
Foo* 
foo; 
public: 
PFoo() : foo(NULL) {} 
PFoo(Foo* f) : foo(f) {} 
operator Foo*() { return foo; } 
Foo* operator->() { return foo; } 
}; 
void f(Foo*); 
PFoo pf(new Foo); 
f(pf); 
// 
Работает благодаря функции operator Foo*() 
pf->MemberOfFoo();
// Работает благодаря функции operator->() 
Причина, по которой работает 
pf->MemberOfFoo()
, менее очевидна. В левой части оператора 
->
указан пользовательский тип, поэтому компилятор ищет перегруженную версию оператора 
->
. Он 
находит ее, вычисляет и заменяет 
pf
возвращаемым значением, которое превращается в новое 
левостороннее выражение оператора 
->
. Этот процесс рекурсивно продолжается до тех пор, пока 
левостороннее выражение не преобразуется к базовому типу. Если таким базовым типом является 
указатель на структуру, указатель на класс или указатель на объединение, компилятор обращается к 
указанному члену. Если это что-то иное (например, 
int
), компилятор злорадно хохочет и выдает 
сообщение об ошибке. В нем он оценивает ваш интеллект и перспективы будущей работы на 
основании того факта, что вы пытаетесь обратиться к члену чего-то, вообще не имеющего членов. В 
любом случае поиск заканчивается при достижении базового типа. Для самых любопытных сообщаю, 
что большинство компиляторов, которыми я пользовался, не отслеживает истинной рекурсии вида: 
PFoo operator->() { return *this; } 
Здесь оператор 
->
пользовательского типа возвращает экземпляр этого типа в качестве своего 
значения. Компиляторы C++ обычно предпочитают помучить вас в бесконечном цикле. 
Итак, у нас появился класс-указатель, который можно использовать везде, где используются указатели 
Foo*
: в качестве аргументов функций, слева от оператора 
->
или при определении дополнительной 
семантики арифметических операций с указателями — всюду, где 
Foo*
участвует в сложении или 
вычитании. 
Параметризованные умные указатели 
Один из очевидных подходов к созданию универсальных умных указателей — использование 
шаблонов. 
template  
class SP { 
private: 
Type* 
pointer; 
public: 


 76 
SP() : pointer(NULL) {} 
SP(Type* p) : pointer(p) {} 
operator Type*() { return pointer; } 
Type* operator->() { return pointer; } 
}; 
void f(Foo*); 
Ptr pf(new Foo); 
f(pf); 
// 
Работает благодаря функции operator Type*() 
pf->MemberOfFoo();
// Работает благодаря функции operator->() 
Этот шаблон подойдет для любого класса, не только для класса 
Foo
. Перед вами — одна из базовых 
форм умных указателей. Она используется достаточно широко и даже может преобразовать указатель 
на производный класс к указателю на базовый класс при условии, что вы пользуетесь хорошим 
компилятором. 
Хороший компилятор C++ правильно обрабатывает такие ситуации, руководствуясь следующей 
логикой: 
1. Существует ли конструктор 
P
, который получает 
Р<Ваr>
? Нет. Продолжаем поиски. 
2. Существует ли в 
Р<Ваr>
операторная функция 
operator P()
? Нет. Ищем дальше. 
3. Существует ли пользовательское преобразование от 
Р<Ваr>
к типу, который подходит под 
сигнатуру какого-либо конструктора 
P
? Да! Операторная функция operator 
Bar*()
превращает 
Р<Ваr>
в 
Bar*
, который может быть преобразован компилятором в 
Foo*

Фактически выражение вычисляется как 
Ptrpf2(Foo*(pb.operator Bar*()))
, где 
преобразование 
Bar*
в 
Foo*
выполняется так же, как для любого другого встроенного 
указателя. 
Как я уже говорил, все должно работать именно так, но учтите — некоторые компиляторы 
обрабатывают эту ситуацию неправильно. Даже в хороших компиляторах результат вложения 
подставляемой (
inline
) операторной функции 
operator Bar*()
во встроенный 
P(Foo*)
может быть совсем не тем, на который вы рассчитывали; многие компиляторы создают вынесенные (а 
следовательно, менее эффективные) копии встроенных функций классов вместо того, чтобы 
генерировать вложенный код подставляемой функции. Мораль: такой шаблон должен делать то, что 
вы хотите, но у компилятора на этот счет может быть другое мнение. 
Иерархия умных указателей 
Вместо использования шаблонов можно поддерживать параллельные иерархии указателей и объектов, 
на которые они указывают. Делать это следует лишь в том случае, если ваш компилятор не 
поддерживает шаблоны или плохо написан. 
class PVoid {
// Заменяет void* 
protected: 
void* 
addr; 
public: 
PVoid() : addr(NULL) {} 
PVoid(void* a) : addr(a) {} 
operator void*() { return addr; } 
}; 
class Foo : public PVoid { 
public: 
PFoo() : PVoid() {} 
PFoo(Foo* p) : PVoid(p) {} 
operator Foo*() { return (Foo*)addr; } 
Foo* operator->() { return (Foo*)addr; } 



Download 1,95 Mb.

Do'stlaringiz bilan baham:
1   ...   45   46   47   48   49   50   51   52   ...   144




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©hozir.org 2024
ma'muriyatiga murojaat qiling

kiriting | ro'yxatdan o'tish
    Bosh sahifa
юртда тантана
Боғда битган
Бугун юртда
Эшитганлар жилманглар
Эшитмадим деманглар
битган бодомлар
Yangiariq tumani
qitish marakazi
Raqamli texnologiyalar
ilishida muhokamadan
tasdiqqa tavsiya
tavsiya etilgan
iqtisodiyot kafedrasi
steiermarkischen landesregierung
asarlaringizni yuboring
o'zingizning asarlaringizni
Iltimos faqat
faqat o'zingizning
steierm rkischen
landesregierung fachabteilung
rkischen landesregierung
hamshira loyihasi
loyihasi mavsum
faolyatining oqibatlari
asosiy adabiyotlar
fakulteti ahborot
ahborot havfsizligi
havfsizligi kafedrasi
fanidan bo’yicha
fakulteti iqtisodiyot
boshqaruv fakulteti
chiqarishda boshqaruv
ishlab chiqarishda
iqtisodiyot fakultet
multiservis tarmoqlari
fanidan asosiy
Uzbek fanidan
mavzulari potok
asosidagi multiservis
'aliyyil a'ziym
billahil 'aliyyil
illaa billahil
quvvata illaa
falah' deganida
Kompyuter savodxonligi
bo’yicha mustaqil
'alal falah'
Hayya 'alal
'alas soloh
Hayya 'alas
mavsum boyicha


yuklab olish