Фундаментальная проблема с динамической памятью в том, что может быть несколько указателей на ту же область памяти. Переустановка значения указателя при освобождении памяти позволяет проверять допустимость данного конкретного указателя, но никак не влияет на все остальные указатели, все еще указывающие на уже освобожденную область памяти. Рассмотрим пример:

int *p(new int(42)); // p указывает на динамическую память

auto q = p;          // p и q указывают на ту же область памяти

delete p;            // делает недопустимыми p и q

p = nullptr; // указывает, что указатель p больше не связан с объектом

Здесь указатели p и q указывают на тот же динамически созданный объект. Удалим этот объект и присвоим указателю p значение nullptr, засвидетельствовав, что он больше не указывает на объект. Однако переустановка значения указателя p никак не влияет на указатель q, который стал недопустимым после освобождения памяти, на которую указывал указатель p (и указатель q!). В реальных системах поиск всех указателей на ту же область памяти зачастую на удивление труден.

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

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

Упражнение 12.7. Переделайте предыдущее упражнение, используя на сей раз указатель shared_ptr.

Упражнение 12.8. Объясните, все ли правильно в следующей функции:

bool b() {

 int* p = new int;

 // ...

 return p;

}

Упражнение 12.9. Объясните, что происходит в следующем коде:

int *q = new int(42), *r = new int(100);

r = q;

auto q2 = make_shared(42), r2 = make_shared(100);

r2 = q2;

<p>12.1.3. Использование указателя <code>shared_ptr</code> с оператором <code>new</code></p>

Как уже упоминалось, если не инициализировать интеллектуальный указатель, он инициализируется как нулевой. Как свидетельствует табл. 12.3, интеллектуальный указатель можно также инициализировать указателем, возвращенным оператором new:

shared_ptr p1; // shared_ptr может указывать на double

shared_ptr p2(new int(42)); // p2 указывает на int со значением 42

Конструкторы интеллектуального указателя, получающие указатели, являются явными (см. раздел 7.5.4). Следовательно, нельзя неявно преобразовать встроенный указатель в интеллектуальный; для инициализации интеллектуального указателя придется использовать прямую форму инициализации (см. раздел 3.2.1):

shared_ptr p1 = new int(1024); // ошибка: нужна

                                    // прямая инициализация

shared_ptr p2(new int(1024));  // ok: использует

                                    // прямую инициализацию

Таблица 12.3. Другие способы определения и изменения указателя shared_ptr

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

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