Здравствуйте, lpd, Вы писали:
lpd>Самое простое это неудобные случаи когда время жизни объекта не совпадает со временем жизни переменной.
это точно также работает и с умными указателями
shared_ptr<Foo> x = ...;
...
x.reset(new Foo());
...
x = y;
...
lpd>И например может быть два объекта со счетчиками ссылок, которые нужно удалять вместе, или с более сложной логикой. Или нужно выделить ресурс в середине одной функции, а освободить в середине совсем другой, не связаной напрямую с первой. Я понимаю, что можно исхитриться, но это же неудобно.
два объекта со счетчиками ссылок которые нужно удалять вместе, ты и на чистом Си не удалишь вместе не нарушив инвариант счетчика ссылок
std::unique_ptr<Foo> bar() {
...
return std::make_unique<Foo>();
}
void buzz(std::unique_ptr<Foo>&& foo) {
...
foo.reset();
...
}
buzz(foo());
lpd>Вообще идея связывать время жизни переменной и какие-то операции по освобождению ресурсов довольно сомнительная. Время жизни переменной — это исключительно синтаксическая вещь, а освобождение ресурсов — императивная операция. И писать обертки над функциями только чтобы создать временную переменную, рассчитывая что где-то компилятор ее удалит, это удалять зубы через нос.
как раз наоборот, компилятор не забудет удалить, а вот кое кто предпочитает писать код с утечками, потому что так "проще"
lpd>Циклические ссылки могут понадобиться, и не всегда это плохая архитектура. С++ получается ограничивает программиста, или заставляет его думать об освобождении памяти.
я не говорил что их невозможно реализовать, но как правило это плохая архитектура
lpd>Я предпочту сборку мусора явному delete/free. Однако городить unique_ptr<>/shared_ptr<> в простых случаях, где не нужен подсчет ссылок, значит делать освобождение памяти неявным без причины, да еще с неудобным синтаксисом. И вот это уже является слепым следованием за фанатиками вроде Майерса.
ну вот чуть выше я предложил пример:
auto x = new X();
auto y = new Y(); // new throws exception here
vs
auto x = std::make_unique<X>();
auto y = std::make_unique<Y>();
в первом случае у тебя утечка памяти, потому что если второй new кинет bad_alloc или конструктор Y кинет исключение, объект на который указывает x не будет удален (предпологается что чуть ниже у тебя есть delete x; delete y;, который не выполнится, если будет выброшено исключение). Если ты попробуешь переписать код так, чтобы этого избежать, то получится жуткая каша, с unique_ptr такой проблемы нет
lpd>Тормозят объекты, выделяемые в большом количестве в цикле или массово. Их и можно удалять вручную, для ускорения сборки мусора. Где-то сборка мусора не подойдет, в таких проектах можно использовать free/delete + умные указатели.
— создание объектов в GC языках — очень быстрая операция, удаление тоже (так как у большинства объектов финализаторы пустые), тормозит stop the world фаза сборки мусора, когда GC останавливает все потоки и помечает все достижимые объекты
— free/delete в современных плюсах, как я уже писал, это code smell, попробуй найди хоть одну причину для их использования, кроме личных предпочтений — ничего не получится, т.к. для любого кейса найдется более подходящий и безопасный вариант нежели new/delete или же malloc/free