Фундаментальная проблема с динамической памятью в том, что может быть несколько указателей на ту же область памяти. Переустановка значения указателя при освобождении памяти позволяет проверять допустимость данного конкретного указателя, но никак не влияет на все остальные указатели, все еще указывающие на уже освобожденную область памяти. Рассмотрим пример:
int *p(new int(42)); //
auto q = p; //
delete p; //
p = nullptr; //
Здесь указатели p и q указывают на тот же динамически созданный объект. Удалим этот объект и присвоим указателю p значение nullptr, засвидетельствовав, что он больше не указывает на объект. Однако переустановка значения указателя p никак не влияет на указатель q, который стал недопустимым после освобождения памяти, на которую указывал указатель p (и указатель q!). В реальных системах поиск всех указателей на ту же область памяти зачастую на удивление труден.
Упражнение 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
r2 = q2;
12.1.3. Использование указателя shared_ptr с оператором new
Как уже упоминалось, если не инициализировать интеллектуальный указатель, он инициализируется как нулевой. Как свидетельствует табл. 12.3, интеллектуальный указатель можно также инициализировать указателем, возвращенным оператором new:
shared_ptr
shared_ptr
Конструкторы интеллектуального указателя, получающие указатели, являются явными (см. раздел 7.5.4). Следовательно, нельзя неявно преобразовать встроенный указатель в интеллектуальный; для инициализации интеллектуального указателя придется использовать прямую форму инициализации (см. раздел 3.2.1):
shared_ptr
//
shared_ptr
//
Таблица 12.3. Другие способы определения и изменения указателя shared_ptr