LINUX.ORG.RU

auto_ptr, shared_ptr, weak_ptr - практика использования

 


1

1

В каких случаях лучше всего использовать тот или иной тип умного указателя? Можно ли проверить с их помощью память на освобождение?

Всем спасибо.

★★★★★

Последнее исправление: CYB3R (всего исправлений: 2)

auto_ptr — один владелец. Характерные применения: локальный объект внутри функции/блока, возвращаемое значение функции, не меняющийся член класса.

shared_ptr — разделяемое владение. Не знаешь какой использовать? Бери шаред!

weak_ptr — используется совместно с shared_ptr для разрывания циклических ссылок.

k_andy ★★★
()

auto_ptr - вообще не юзать(он теперь deprecated).

unique_ptr - уникально владеет объектом, т.е. никто другой им не владеет и как только unique_ptr разрушается, объект удаляется, умеет передавать владение другому unique_ptr, может лежать в контейнерах.

shared_ptr - реализует подсчет ссылок. Используется в случае, когда один объект доступен из разных мест, каждый shared_ptr является владельцем объекта, есть счетчик таких shared_ptr для каждого объекта и когда разрушается shared_ptr, счетчик уменьшается, когда shared_ptr копируется - счетчик увеличивается. Как только счетчик становится 0(уничтожен последний shared_ptr, то удаляется и объект). Счетчик потокобезопасен.

weak_ptr - «слабый» указатель на объект, находящийся во владении shared_ptr'ов. Не учитывается в вышеописанном счетчике, не дает прямого доступа к объекту. Имеет метод получения shared_ptr'а на указываемый объект. Если объекта уже нет, то будет возвращен нулевой shared_ptr, если объект есть, то будет создан обычный shared_ptr на него(т.е. увеличен счетчик и т.д.), что не даст удалить объект, пока к нему будет осуществляться доступ(будет жить shared_ptr). weak_ptr используется, в основном, для ручного разруливания циклических ссылок, а так же для кэширования и подобных задач(аналогично java'вовским WeakReference и SoftReference).

anonymous
()

При нормальном использовании освобождение гарантируется.

anonymous
()

Как они называются, так и применяй. unique_ptr для уникального владения, shared_ptr - для расшаренного объекта, weak_ptr для необязательного указателя на объект, котролируемый одним или несколькими shared_ptr.

anonymous
()
Ответ на: комментарий от andreyu

Основной причиной является наличие std::unique_ptr.

Из-за отсутствия в старом стандарте move-семантики, создателям auto_ptr пришлось делать нестандартное поведение конструктора копирования и оператора присваивания, хотя лучше бы они так не делали. boost::scoped_ptr в этом отношении и то более продуман и для старого стандарта я бы рекомендовал использовать его.

В новом же есть unique_ptr, полноценно реализующий изначальную задумку указателя, единовластно владеющего ресурсом. Какой смысл теперь использовать auto_ptr? Никакого.

anonymous
()

Ответ — не использовать говноязыки. Использовать нормальный язык.

Например, Common Lisp.

anonymous
()
Ответ на: комментарий от anonymous

CL ничем не лучше С++. Ладно бы еще Scala или F# посоветовали. Ну clojure хотя бы... Впрочем, плюсы все равно будут нужны - иногда программам нужно работать быстро или хотя бы иметь потенциал по оптимизации. Как мне в CL написать свой аллокатор?

anonymous
()
Ответ на: комментарий от Chaser_Andrey

Говноязык - любой язык, что не лисп

Неговноязык - лисп

Глупые вопросы ты задаешь :)

mono ★★★★★
()
Ответ на: комментарий от anonymous

ты не понимаешь сути лиспа. Лисп - это не «ой, мальчики, я тут написала свой аллокатор». Это не классы ради классов и черезжопная реализация ООП там, где она не нужна. Это впихивание ассемблерных вставок для того, чтобы хоть как-то ускорить убогий тормозной алгоритм со сложностью O(x^n). Это не сообщения об ошибках, в три раза превыщающие по размеру код, вызвавший ошибку. Лисп - это простой и мощный язык для старых усталых чуваков, пишущих индустриальный софт с кучей скобочек, макросов, лямбд и замыканий. Вот и всё.

p.s. капча lispis friends намекает.

anonymous
()
Ответ на: комментарий от Chaser_Andrey

Из-за неочевидного поведения.

Поведение действительно неочевидное. Но это оговорено, так что жить не мешало.
Я очень много где использовал и использую auto_ptr.

С другими смарт-поинтерами такой хрени нету.

Это да.

andreyu ★★★★★
()
Ответ на: комментарий от anonymous

В новом же есть unique_ptr, полноценно реализующий изначальную задумку указателя, единовластно владеющего ресурсом. Какой смысл теперь использовать auto_ptr? Никакого.

Когда его можно будет под ios и android использовать не боясь наступить на внезапно появившиеся грабли?

andreyu ★★★★★
()
Ответ на: комментарий от k_andy

shared_ptr — разделяемое владение. Не знаешь какой использовать? Бери шаред!

так и делай. Борись с размазанным владением. Борись с циклическими ссылками. Борись с объектами которые живут произвольно долго.

Если отбросить сарказм —

scoped_ptr — объект живёт в пределах области видимости. Как объект на стеке, только не обязательно на стеке. Используется как гвард для пущей exception safety.

unique_ptr — объект живёт произвольно долго. Один владелец определяет время смерти объекта. Нету конструктора копирования, есть move-конструктор. Используется для выражения эксклюзивного владения. Если надо копирование — можно сделать в копирующем конструкторе объекта копию сущности на которую ссылается unique_ptr. ИМХО — главный указатель в stl.

shared_prt — объект живёт произвольно долго. Несколько владельцев (по последнему) определяют время смерти объекта. Используется в многопоточных приложениях и для передачи многопоточным third-party либам. Среди минусов — размывает владение. В однопоточном приложении становится намного сложнее понять кто и когда убивает объект. Потому используется только тогда, когда без него нельзя. Кроме того, у shared_prt нельзя забрать владение. weak_ptr используется вместе с shared_prt как не владеющий указатель, который может ответить на вопрос «жив ли ещё объект?»

Кроме таких указателей в boost ещё есть специальные ptr-контейнеры. Владеющие контейнеры, которые позволяют хранить и контролировать время жизни многих объектов в куче, например.

Remington
()

auto_ptr для exception save програмирования. ещё можно использовать для методики написания „классов без деструкторов“.

class SomeClass
{
	...
	public:
                SomeClass() : dev_(0) {}
		~SomeClass() {delete dev_;}
	private:
		Device *dev_;
	...
};

int SomeClass::SomeClass(SomeBusParameters &bp, DeviceIdent &di)
{
	std::auto_ptr <Device> d;
	std::auto_ptr <Bus> b;
	try {
		b.reset(new Bus(bp));
		d.reset(new Device(b.get(), di));
		d->do_this();
		d->do_that();
		d->do_formatC();
	} catch (DeviceException &e) {
                do_log("AAA!!! Девице фейл!");
		return e.code();
	} catch (BusException &e) {
                do_log("AAAA!!!! Bus fahrer ist betrunken!!!);
                return e.code();
        } catch (std::exception &e) {
                do_log("Holly shit!!! МымымымontserKill!!!!");
                return e.code();
        }
	delete dev_;
	dev_ = d.release();
}
если сделать SomeClass::Device автоптром, то можно убрать спискок инициализцамии, деструктор и смело удалять все строчки, где есть delete dev_

shared_ptr - это примитивный уборщик мусора. можно крутить туда сюда в std::list’ах или std::vector’ах например, но писать код для удаления без delete’ов. erase сделал и всё. деструкторы также не нужны, если контейнет - член класса например.

class SomeClass
{
	public:
		void addDevice(DeviceIdent &);
	...
	private:
		std::list <std::shared_ptr <Device> > devs_;
	...
}


void SomeClass::addDevice(DeviceIdent &id)
{
	std::shared_ptr <Device> dev(DeviceFactory::create(id));
	devs_.push_back(dev);
}
последний пример exception save. да и класс сам по себе - если его удаляют - автоматом удалит всех девиц.

weak_ptr никогда не доводилось использовать. unique_ptr - тот же auto_ptr, но можно хранить в stl контейнерах. auto_ptr так не умеет, известный факт. именно по этому он deprecated.

nanoolinux ★★★★
()
Ответ на: комментарий от Remington

там где я работаю запрещено использовать буст. такое тоже бывает, да. а ещё эти гады заставляют меня юзать проклятый свн и это только вершина айсберга.

nanoolinux ★★★★
()
Ответ на: комментарий от nanoolinux

так бывает. Решается портированием буста к себе в коммоны. проблема с смарт-поинтерами в контейнерах — лютый оверхед по выделению маленьких объектов и лютая неэффективность

Remington
()
Ответ на: комментарий от nanoolinux

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

Remington
()
Ответ на: комментарий от Remington

это, конечно, частный случай и, безусловно, сложность алгоритмов должна оптимизироваться раньше, но мне этот пример запомнился как очень эффектный пример почему же всё-таки не стоит использвать шаред-птр-ы в векторах/деках/листах

Remington
()
Ответ на: комментарий от Remington

Борись с размазанным владением. Борись с циклическими ссылками. Борись с объектами которые живут произвольно долго.

Хыхы. На аватарку ТСа посмотри.

k_andy ★★★
()
Ответ на: комментарий от Remington

который может ответить на вопрос «жив ли ещё объект?»

Собственно, это ключевой вопрос, поскольку с обычным указателем невозможно узнать освободилась ли уже память, занятая объектом, или еще нет.

LongLiveUbuntu ★★★★★
() автор топика
Ответ на: комментарий от LongLiveUbuntu

Ну такое. В моей практике знать ответ на этот вопрос надо было всего пару раз. Обычно тебе просто надо быть уверенным, что время жизни объекта достаточно длинно и в тоже время ограничено строго определённым событием.

Remington
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.