Добавил:
t.me Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

2 семестр / Литература / Язык программирования С++. Краткий курс. Страуструп

.pdf
Скачиваний:
9
Добавлен:
16.07.2023
Размер:
31.34 Mб
Скачать

11

О

Глава

5.

Основные

операции

пользования. дескрипторы

Примерами ресурсов являются

память, блокировки,

сокеты,

файлов и потоков. Нет никакого

сюрприза в том, что

ресурс,

который

является

не

просто

памятью,

называется

ресурсом,

не

являющимся

памятью

(non-memory resource).

Хорошая

система

управления

ресурсами

обрабатывает

все

разновидности

ресурсов.

Утечек

следует

избегать

в

любой

системе, работающей длительное время,

но

чрезмерное удержание

ресурсов

может быть

почти таким же плохим, как

и

утечка. Например, если

система

удерживает

память, блокировки, файлы и тому подобное в два раза дольше,

чем требуется, -

потенциально такой системе требуется вдвое большее коли­

чество

ресурсов.

Прежде чем прибегать к сборке мусора,

систематически используйте де­

скрипторы ресурсов: пусть каждый ресурс

имеет владельца в некоторой об­

ласти видимости и по умолчанию освобождается в конце области видимости

его владельца. lnitialization -

В С++

это называется идиомой RAII (Resource Acquisition ls

захват

ресурса есть инициализация) и интегрируется с обра­

боткой

ошибок

в

форме

исключений.

Ресурсы

могут

перемещаться

из

одной

области

видимости

в

другую

с

помощью семантики

перемещения

или

"ин­

теллектуальных

указателей'',

а

совместное

владение

может

быть

представле­

но

"совместно используемым указателем" (§13

.2.1 ).

В

стандартной

библиотеке С++

идиома

RAll

очень

распространена

для

разных

видов

ресурсов,

например

для

памяти

(string,

vector,

map,

unordered

_map

и

т.д.), файлов

(ifstream,

ofstream

и

т.д.),

потоков

вы­

полнения

(thread),

блокировок

(lock

_

guard,

unique

_

lock

и

т.д.)

и

объ­

ектов

общего

назначения

(через

unique

_ptr

и

shared_ptr).

Результатом

является

неявное

управление

ресурсами,

невидимое

при

обычном

использо­

вании

и

приводящее

к

малой

продолжительности

захвата

ресурсов.

5.4.

Обычные

операции

Некоторые

операции

при

их

определении

для

типа

имеют

обычный

смысл.

Этот

обычный

смысл

часто

предполагается

программистами

и

библиотеками

частности,

стандартной

библиотекой),

поэтому

разумно

соответствовать

ему

при

разработке

новых типов,

для

которых

эти

операции

имеют

смысл.

• • • • • •

Сравнения: ==, ! =, <, <=, > и >= (§5.4.1 ).

Операции с контейнерами: size (), begin ()

Операции ввода-вывода:>> и<< (§5.4.3).

Пользовательские литералы (§5.4.4). swap () (§5.4.5). Хеш-функции: hash<> (§5.4.6).

и

end

()

(§5.4.2).

5.4.

Обычные

операции

111

5.4.1.

Сравнения

Смысл

сравнения

на

равенство(==

и

!

=)тесно

связан

с

копированием. По­

сле

копирования

копии

должны

рассматриваться

как

равные

(эквивалентные)

объекты:

Ха =

ХЬ =

assert

нечто; а; (а==Ь);

//

Если

здесь

а

!=Ь,

"нечто"

очень

странное

(§3.

5.

4)

Одновременно

с

==

определите

также

!=

и

убедитесь,

что

а!

означает

! (а==Ь).

Аналогично, если вы определяете оператор <, то определите

торы<=,>,>= и убедитесь в выполнении обычных тождеств:

также

опера­

• • •

а<=Ь означает

(а<Ь)

11

(а==Ь)

и

! (Ь<а).

а>Ь означает Ь<а.

 

 

 

 

а>=Ь означает

(а>Ь)

11

(а==Ь)

и

! (а<Ь).

Чтобы

оба

операнда

бинарного

оператора

трактовались

одинаково,

его

лучше

всего

определить

как

свободную

функцию

в

пространстве

имен

соот­

ветствующего

класса.

Например:

namespace

NX

{

 

class

Х

11 ...

);

 

bool

operator==(const

/ / ...

);

 

Х&,

const

Х&);

5.4.2.

Операции

с

контейнерами

Если

только

у

вас

нет

по-настоящему

веской

причины

поступать

иначе,

проектируйте

контейнеры

в

стиле

контейнеров стандартной

библиотеки

(гла­

ва

11,

"Контейнеры").

В

частности,

сделайте

контейнер

безопасным

с

точки

зрения

ресурсов,

реализуя

его

как

дескриптор

с

соответствующими

суще­

ственными операциями (§5.1.1, §5.2).

Контейнеры стандартной библиотеки

знают

количество

хранящихся

в

них

элементов,

и

мы

можем

получить

его

с

помощью

вызова

size

().Например:

for(size с [i]

t =

i=O; О;

i<c.size();

++i)

// //

size_t size()

- в

имя возвращаемого типа стандартной библиотеке

5.4.

Обычные

операции

113

123.

456

представляет

собой

douЫe.

"Surprise

!

"представляет

собой

const

char

[10].

Может

быть

полезным

предоставить

подобные

литералы

для

пользователь­

ских

типов.

Это

делается

путем

определения

смысла

подходящего

суффикса

литерала,

поэтому

мы

можем

получить

следующее.

"Surprise!

"s

представляет

собой

std:

:string.

• •

123s представляет собой секунды.

 

 

12. 7 i является мнимым числом, так что 12.

7i +4 7 представляет собой

комплексное число (в данном случае -

{47,

12. 7} ).

В

частности,

в

стандартной

библиотеке

с

использованием

соответствую­

щих

заголовочных

файлов

и

пространств

имен

мы

получаем

доступ

к

следу­

ющим

суффиксам.

<chrono>

Суффиксы стандартной библиотеки для

литералов

std::literals: :chrono literals

h, min,

s,

ms, us,

ns

<string> <string_view> <complex>

std: :literals::string_literals std: :literals::string literals std::literals::complex_literals

s sv i,

il,

if

Неудивительно,

что

литералы

с

такими

определяемыми

пользовате­

лем

суффиксами

называются

пользовательскими

литералами

(user-defined

literal -

UDL).

Они

определяются

с

использованием

литеральных

операто­

ров.

Литеральный

оператор

преобразует

литерал

типа

своего

аргумента

в

его

возвращаемый

тип.

Например,

суффикс

i

для

мнимых

чисел

может

быть

реа­

лизован

следующим

образом:

/

/

Мнимые

числа:

constexpr

complex<douЫe>

{

 

 

 

 

 

return

{0,arg);

operator""i(long

douЫe

arg)

Здесь

operator"" указывает, что мы определяем литеральный

оператор;

i

после индикатора литерального оператора " " представляет собой

суффикс, для которого оператор определяет его значение;

 

тип аргумента, long douЫe, указывает, что суффикс (i)

определен для

литералов с плавающей точкой;

 

[6]

[7]

[8]

[9]

(10]

[11]

(12]

(13]

(14]

[15]

5.5.

Советы

115

Если у класса есть пользовательский деструктор, ему, вероятно, требу­

ются пользовательские или удаленные операции копирования и

переме­

щения; §5.2.1.

 

 

По умолчанию объявляйте конструктор с единственным

аргументом как

explici t; §5.1.1; [CG:C.46].

 

 

Если член доставьте [CG:C.48].

класса имеет подходящее значение по умолчанию, пре­

соответствующий

инициализатор

члена-данных;

§5.1.3;

Переопределите или запретите копирование, если копирование по умол­

чанию не годится для вашего типа; §5.2.1, §4.6.5; (CG:C.61].

Возвращайте контейнеры по значению

(полагаясь на эффективное пере­

мещение); §5.2.2; [CG:F.20].

 

 

 

Для больших операндов используйте в

качестве типов аргументов кон­

стантные ссылки; §5.2.2; (CG:F.16].

 

 

Обеспечьте строгую безопасность ресурсов -

никогда не допускайте

утечки того, что можно рассматривать как ресурс; §5.3; [CG:R.1 ].

Если класс представляет собой

дескриптор

ресурса, ему требуются

пользовательские конструктор,

деструктор и

операции копирования;

§5.3; (CG:R.1 ].

 

 

 

Перегружайте операции, имитируя их обычное использование; §5.4;

(CG:C.160].

 

 

 

Следуйте принципам проектирования контейнеров стандартной библи­

отеки; §5.4.2; [CG:C. l 00].

 

 

 

6 Шаблоны

• •

Место для вашей цитаты.

-

Б. Страуструп

Введение

 

Параметризованные типы

 

Ограниченные аргументы

шаблона

Аргументы-значения шаблонов

Вывод аргументов шаблона

Параметризованные операции

Шаблоны функций

 

Функциональные объекты

 

Лямбда-выражения

 

Шаблонные механизмы

 

Шаблоны переменных

 

Псевдонимы

 

if времени компиляции

 

Советы

 

6.1.

Введение

Тому, douЫe.

кому нужен вектор,

Вектор -

это общая

вряд ли всегда концепция, не

будет нужен зависящая от

именно понятия

вектор числа

с

плавающей

точкой.

Следовательно,

тип

элемента

вектора

должен

быть

представлен

независимо

от

самого

вектора.

Шаблон

-

это

класс

или

функ­

ция,

которую

мы

параметризуем

с

помощью

набора

типов

или

значений.

Мы

используем

шаблоны

для

представления

идей,

которые

лучше

всего

воспри­

нимаются

как

нечто

общее,

из

которого

мы

можем

генерировать

конкрет­

ные

типы

и

функции,

указывая

аргументы,

такие

как

тип

douЫe

элемента

vector.