Операторы доступа к элементам (точка и стрелка) не поддерживаются указателями unique_ptr на массивы. Другие его функции неизменны
unique_ptr uu может указывать на динамически созданный массив типа T
unique ptr u(p)u указывает на динамически созданный массив, на который указывает встроенный указатель p. Тип указателя p должен допускать приведение к типу T (см. раздел 4.11.2). Выражение u[i] возвратит объект в позиции i массива, которым владеет указатель u. u должен быть указателем на массив

В отличие от указателя unique_ptr, указатель shared_ptr не оказывает прямой поддержки управлению динамическим массивом. Если необходимо использовать указатель shared_ptr для управления динамическим массивом, следует предоставить собственную функцию удаления:

// чтобы использовать указатель shared_ptr, нужно предоставить

// функцию удаления

shared_ptr sp(new int[10], [](int *p) { delete[] p; });

sp.reset(); // использует предоставленное лямбда-выражение, которое в

// свою очередь использует оператор delete[] для освобождения массива

Здесь лямбда-выражение (см. раздел 10.3.2), использующее оператор delete[], передается как функция удаления.

Если не предоставить функции удаления, результат выполнения этого кода непредсказуем. По умолчанию указатель shared_ptr использует оператор delete для удаления объекта, на который он указывает. Если объект является динамическим массивом, то при использовании оператора delete возникнут те же проблемы, что и при пропуске [], когда удаляется указатель на динамический массив (см. раздел 12.2.1).

Поскольку указатель shared_ptr не поддерживает прямой доступ к массиву, для обращения к его элементам применяется следующий код:

// shared_ptr не имеет оператора индексирования и не поддерживает

// арифметических действий с указателями

for (size_t i = 0; i != 10; ++i)

 *(sp.get() + i) = i; // для доступа к встроенному указателю

                      // используется функция get()

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

Упражнения раздела 12.2.1

Упражнение 12.23. Напишите программу, конкатенирующую два строковых литерала и помещающую результат в динамически созданный массив символов. Напишите программу, конкатенирующую две строки библиотечного типа string, имеющих те же значения, что и строковые литералы, используемые в первой программе.

Упражнение 12.24. Напишите программу, которая читает строку со стандартного устройства ввода в динамически созданный символьный массив. Объясните, как программа обеспечивает ввод данных переменного размера. Проверьте свою программу, введя строку, размер которой превышает длину зарезервированного массива.

Упражнение 12.25. С учетом следующего оператора new, как будет удаляться указатель pa?

int *pa = new int[10];

<p>12.2.2. Класс <code>allocator</code></p>

Важный аспект, ограничивающий гибкость оператора new, заключается в том, что он объединяет резервирование памяти с созданием объекта (объектов) в этой памяти. Точно так же оператор delete объединяет удаление объекта с освобождением занимаемой им памяти. Обычно объединение инициализации с резервированием — это именно то, что и нужно при резервировании одиночного объекта. В этом случае почти наверняка известно значение, которое должен иметь объект.

Когда резервируется блок памяти, обычно в нем планируется создавать объекты по мере необходимости. В таком случае желательно было бы отделить резервирование памяти от создания объектов. Это позволит резервировать память в больших объемах, а дополнительные затраты на создание объектов нести только тогда, когда это фактически необходимо.

Зачастую объединение резервирования и создания оказывается расточительным. Например:

Перейти на страницу:

Похожие книги