C++ lectures at MIPT (in Russian). Lecture 9. Smart pointers, part 1
HTML-код
- Опубликовано: 3 окт 2024
- Лекции в магистратуре МФТИ по C++ на русском языке.
Эта лекция посвящена очень простым и базовым вещам: владению ресурсами (и в частности памятью) и моделям такого владения.
Заканчивается лекция рассмотрением вариантных типов
Лектор: Константин Владимиров
Дата лекции: 26 ноября 2019 года
Съёмка и звук: Дмитрий Рябцев
Предыдущая лекция: • C++ lectures at MIPT (...
Следующая лекция: • C++ lectures at MIPT (...
Слайды ко всем лекциям: sourceforge.ne...
Errata:
пока здесь пусто
Супер лекции!
Большое спасибо за все лекции, до просмотра этого видео кучу раз читал, но ни разу не понимал смартпоинтеры, теперь ситуация точно проясняется.)
Вот я вроде бы всё понимаю в лекциях, тяну руку и правильно отвечаю(за монитором самому себе :D) но когда вы говорите подумать дома над какой-то задачкой, то у меня идей вообще нет... Надеюсь со временем, когда количество знаний увеличиться, то я смогу обдумывать решения таких задач! Спасибо за лекции!
А что именно из заданий в этой лекции вызвало затруднения и почему?
Такое ощущение, что нечто важное и нетривиальное пропущено в цикле - лябды. В лекции они упоминаются как нечто известное всем слушателям.
Лямбды будут на своём месте -- перед алгоритмами. Базовые вещи о них были сообщены в первых лекциях. Детали последуют.
@@tilir прошу прощения, это я случайно перескочил между курсами. В старом курсе были лямбды в начале, поэтому все ими оперируют.
По поводу замечания, что интерфейс голого указателя предполагает, что ему всегда можно сделать delete. Это порождает довольно интересный спор по поводу, а вот мне нужно в функцию передать указатель, но без передачи владения, чтобы она там что-то поделала с ним или целевым объектом и все. Если по фен-шую, у нас везде умные указатели и мы не хотим, чтобы утек голый указатель, то надо передавать по константной ссылке на unique_ptr. Но это жесть: const std::unique_ptr& param. А если это библиотека, и не факт, что там будет unique_ptr, а не shared_ptr? Знаю ещё, что в core guidelines есть owner, чтобы показать, что вот тут мы указателем владеем, во всех остальных случаях сырой указатель это значит, что не владеем и delete делать не следует. А вы какой стратегии придерживаетесь?
Ссылка на unique_ptr звучит для меня очень странно. Вы либо передаёте просто по ссылке. Либо умный указатель по значению, т.к. у нас и так ссылочная семантика для указателей.
Я плохо могу представить зачем вам передавать голый указатель не передавая владения. Разве что какая-нибудь реализация дерева, например, но пока это в приватной части это терпимо.
5:55
T& operator*() const
(Если мы хотим сохранять дизайн обычного поинтера)
30:00
unique_ptr& operator=(unique_ptr&& rhs) {
delete ptr_;
ptr_ = rhs.ptr_;
rhs.ptr_ = nullptr;
return *this;
}
(По смыслу мы же хотим передать владение от rhs к *this, а не обменять владение)
(1) Согласен. Но там в коде есть гораздо худшая логическая ошибка.
(2) Зачем? Смотрите: после A = move(B), B переходит в moved-from состояние. То есть согласованное но непредсказуемое. Вариантом этого состояния является прошлое состояние A. Нет никаких оснований тут вызывать сравнительно дорогой delete. По семантике вполне безопасно просто поменять (и это быстрее).
@@tilir (2) Ok. Но тогда нужно сделать swap(ptr_, rhs.ptr_); При swap(*this, rhs) сейчас будет stackoverflow.
На 17 слайде наверное ошибка. Конструктор копирования unique_ptr(const unique_ptr &rhs) = delete а не unique_ptr(unique_ptr &rhs) = delete
Нет разницы. Обе формы это допустимые формы для copy ctor. Запрет любой из них это запрет копирования.
Будет ли раскрыта тема intrusive pointers? Ну хотя бы на примере boost::intrusive_ptr. Их использование бывает необходимо, когда код на C++ интегрируется с кодом на динамических языках
Да, это будет во второй части ))
Константин, мне непонятно почему возвращать сырой указатель из самописного "умного" указателя это плохо. Понятно, что к нему могут применить delete. Но ведь и из std::string можно получить сырой указатель на первый символ и применить delete. Мне кажется, если кто-то применяет delete к сырому указателю, не выделив перед этим память, то он ССЗБ. Поэтому, как мне кажется, возвращать сырой указатель - это нормально...
А еще в функцию bar можно было передать ссылку на scoped_ptr.
У строки есть иное предназначение. Это строка, она предоставляет интерфейс строки, итераторы и всё такое
У умного указателя есть только одно предназначение: владеть объектом и управлять его временем жизни. Как только ресурс утёк по сырому указателю, умный указатель лишается смысла. И delete там не худшее что может произойти. Например если у вас есть unique_ptr и вы обещаете что он не утёк, он, с точки зрения многопоточности, ведёт себя как int: достаточно мьютекса вокруг доступов. А если он утёк, то он не лучше чем указатель: тот же ресурс может в этот момент модифицировать другой поток и т.п.
1:02:59 - для тех, кто не нашёл доклад, я вот нашёл ) ruclips.net/video/JfmTagWcqoE/видео.html
Самая забаная концовка )
Страница 36 (1:07:22) Почему же тогда vector::top возвращает ссылку на T, а не просто T? Ведь если мы предоставляем интерфейс с ссылкой на T&, то в некоторой степени мы сами способствуем сомнительному использованию нашего метода как в примере: const auto& x = v.top();
Да, это худший способ использовать вектор неправильно. Эта ссылка ещё и провиснуть может.
Увы, когда его проектировали в 92-м, до правых ссылок оставалось лет десять и возвращение по значению казалось дорогим
@@tilir спасибо за ответ и спасибо за очень интересные лекции!
По поводу 55-60 минут. Для того, чтобы сделать pimpl с unique_ptr не нужно писать кастомный делетер. Достаточно написать:
##########.h
struct MyClass {
public:
~MyClass();
private:
class pImpl;
const unique_ptr impl;
};
#######.cpp
MyClass::~MyClass() = default;
Мне кажется т.к. для делетера тоже объявлять структуру, то объявить её для внутреннего применения менее интрузивно чем делать обёртку. Но метод вполне имеющий место быть, спасибо за дополнение ))
@@tilir Хоть я и привел этот пример, но после лекции он выглядит для меня, как некая "магия") Не могли бы Вы объяснить, почему это работает? Т.е. почему прототип деструктора для класса позволяет компилятору создать unique_ptr на неполный тип?
Основная проблема unique-ptr для pimpl это то что у него в деструкторе delete требует полный тип. Если вы его врапаете то требования к деструктору уходят в деструктор враппера, а его вы как раз откладываете. Схема в целом та же что и с откладыванием через делетер, но снаружи, а не изнутри.
А что делать если нужен динамический массив с неизменяемым размером? Т.е. std::vector без capacity
unique_ptr для массива?
А нельзя было бы просто модифицировать auto_ptr сделать его так как работает unique_ptr и не создавать дополнительный умный указатель?
И сломать все мегабайты существующего кода, закладывающиеся на копируемость auto_ptr?
@@tilir Всё равно он помечен на удаление в 17, или получается дали людям время на исправления.
Да, конечно
Слйд 29, ruclips.net/video/JrWl5INQybE/видео.html
Разве нельзя использовать вместо unique_ptr c; unique_ptr c; ?
cl и gcc8 позволили.