Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Умные указатели


Автор: Tiarwe 25.1.2013, 18:37
Здравствуйте! Изучаю умные указатели и что-то совсем запутался... Вначале опишу, что мне нужно.
Есть класс Book и vector из указателей на эти книги. Вот захотелось мне, чтобы это были не обычные указатели, а умные...
1) В чём разница между shared_ptr и auto_ptr? Правильно ли я понимаю, что при auto_ptr на объект может ссылаться лишь один указатель, в то время как при shared_ptr - множество (т.к. идёт подсчёт ссылок)? При этом, если auto_ptr перестаёт указывать на объект, то он уничтожается? Ровно как и shred_ptr, когда кол-во ссылок равно 0?
2) Вернёмся к вектору. Пускай в нём 1000 умных указателей на объекты. И мне например захотелось удалить 200 объектов... Т.е. мне надо всего-лишь удалить указатели из вектора и больше ни о чём не беспокоиться?
3) Или на примере игры... есть Object и вектор из 100 Target'ов. Object имеет в себе указатель на один из Target'ов... Эти самые 100 Target'ов должны быть именно shared_ptr, т.к. на них ещё могут ссылаться из вне?
В общем, каша в голове  smile 

Автор: mes 25.1.2013, 18:47
если речь о векторе про ауто_птр можно сразу забыть...

Цитата(Tiarwe @  25.1.2013,  17:37 Найти цитируемый пост)
 Правильно ли я понимаю, что при auto_ptr на объект может ссылаться лишь один указатель,

не совсем..  ауто_птр владеет одним обьектом, при копировании передаёт все права с обьектом другому ауто_птр, а при разрушении удаляет обьект коим владеет.. 

Автор: bsa 25.1.2013, 23:12
Tiarwe, auto_ptr такая своеобразная штука, что лучше ей не пользоваться. Если не знаешь для чего она нужна. Сейчас ее имеет смысл использовать только для контроля времени жизни динамического объекта по типу автоматических. Хотя для этого есть (в boost) более подходящая штука - scoped_ptr. Которая ведет себя более предсказуемо без чтения документации.

Автор: EvilsInterrupt 26.1.2013, 16:14
Tiarwe, Читай книгу Джосьютиса "Стандартная библиотека C++". Там описан std::auto_ptr во всех красках, описаны его ограничения и его возможности, а также нюансы. После его описания в это книге приведен пример кода умного указателя с подсчетом ссылок.

Автор: EvilsInterrupt 26.1.2013, 23:43
Tiarwe,
Я бы юзал не вектор указателей, а список указателей. Посмотрите в сторону других контейнеров отличных от std::vector, к примеру std::list. Во внутренней реализации этого контейнера как правило участвуют указатели( не те что хранятся в этом контейнере, в контейнере может храниться любой тип хоть SuperPuperMatreshka). Обратите внимание на слово "complexity" http://en.cppreference.com/w/cpp/container

Добавлено через 1 минуту и 34 секунды
А вот другая http://upload.cppreference.com/mwiki/images/e/e7/container-library-overview-2012-12-27.pdf

Автор: borisbn 27.1.2013, 18:01
EvilsInterrupt, в чём сермяжная правда отказа от вектора? Если уж так любишь ссылаться на книги, почему не привести цитату из Майерса:
Цитата
Если не знаете какой контейнер выбрать - берите вектор

За точность цитаты не ручаюсь, за смысл - да

Автор: mes 27.1.2013, 19:07
Цитата(EvilsInterrupt @  26.1.2013,  22:43 Найти цитируемый пост)
 Во внутренней реализации этого контейнера как правило участвуют указатели( не те что хранятся в этом контейнере, в контейнере может храниться любой тип хоть SuperPuperMatreshka). 

 smile  smile  smile 

Автор: Dem_max 27.1.2013, 19:53
Почитай тут все расжевано
http://www.rsdn.ru/article/cpp/smartptr.xml

Автор: EvilsInterrupt 28.1.2013, 01:16
Цитата(borisbn @  27.1.2013,  19:01 Найти цитируемый пост)
Если не знаете какой контейнер выбрать - берите вектор

Это если не знать! Вектор как правило имеет смысл выбирать если нужно непрерывную область, так сказать C-стайл, сейчас его вроде как std::array может заменить в этом, судя по описанию на cppreference.

Более того в постановке задачи:
Цитата

Есть класс Book и vector из указателей на эти книги

и:
Цитата

Пускай в нём 1000 умных указателей на объекты


Ни одного намека на то что человеку нажно хранить книги в С-подобном виде, т.е. последовательно в файле. Зато указано 1000 !!!! Т.е. человек предполагает что ему надо будет достаточно часто вставлять. Другое из постановки задачи:
Цитата

И мне например захотелось удалить 200 объектов...


Вы все еще уверены в векторе? Удалить 200 штук, добавить 1000...

Автор: borisbn 28.1.2013, 09:16
Цитата(EvilsInterrupt @  28.1.2013,  01:16 Найти цитируемый пост)
 Вектор как правило имеет смысл выбирать если нужно непрерывную область, так сказать C-стайл, сейчас его вроде как std::array может заменить в этом

1) то, что в векторе память непрерывная - спорить глупо, но его чаще выбирают по другим причинам (правда, являющимся следствием непрерывности) - random acces за постоянное время и т.п.
2) std::array заменил массивы типа
Код
T array[ 100 ];

а ни разу не вектор

Цитата(EvilsInterrupt @  28.1.2013,  01:16 Найти цитируемый пост)
Вы все еще уверены в векторе? Удалить 200 штук, добавить 1000... 

По поводу добавить - уверен:
http://liveworkspace.org/code/2eY9uN$9
По поводу удалить - подумай во над чем: прежде чем удалить элемент из контейнера его нужно там найти. Тест поиска элемента в векторе и в листе написать ? или и так понятно ?

Автор: EvilsInterrupt 28.1.2013, 10:37
borisbn
Вы правы! Спасибо за аргументацию, которую можно "пощупать" и "потрогать". Нельзя мне в 2 ночи посты писать, каюсь! ;)

Автор: mes 28.1.2013, 19:49
Цитата

По поводу добавить - уверен:

и это еще .reserve не использован ))

справедливости ради надо отметить, большая разница, вставлять в конец или в начало.. 

Автор: bsa 29.1.2013, 14:19
Цитата(mes @  28.1.2013,  20:49 Найти цитируемый пост)
справедливости ради надо отметить, большая разница, вставлять в конец или в начало.. 

Если честно меня удивляет, почему разработчики STL не сделали такую простую штуку, как возможность добавлять в начало вектора с такой же сложностью, как и в конец. Реализуется это всего лишь одним дополнительным указателем внутри класса и тройкой методов (reserve_front(), push_front(), pop_front()).

Автор: baldina 29.1.2013, 14:44
Цитата(bsa @  29.1.2013,  14:19 Найти цитируемый пост)
Реализуется это всего лишь одним дополнительным указателем внутри класса

vector должен быть непрерывным от &v[0]

Добавлено @ 14:47
есть же deque<>, тут вам и такая же временная сложность, и добавление в начало.
лишь непрерывность не гарантирована

Автор: bsa 29.1.2013, 15:43
Цитата(baldina @  29.1.2013,  15:44 Найти цитируемый пост)
vector должен быть непрерывным от &v[0]
А кто мешает? Просто сейчас добавление в начало всегда приводит к сдвигу всех элементов, а в случае с дополнительным указателем - сдвигалось бы только начало массива (если резерв перед данными есть):
Код
template<class Type, class Allocator>
class vector
{
private:
   Type *area_beg_; //нужно добавить
   Type *data_beg_; //остальные три уже есть
   Type *data_end_;
   Type *area_end_;
};
главное условие: area_beg_ <= data_beg_ <= data_end_ <= area_end_
Если data_end_ == data_beg_, то вектор пуст
Если area_end_ == area_beg_, то вектор не имеет резерва (и пуст).
Если area_beg_ < data_beg_, то у вектора есть резерв перед началом
Если data_end_ < area_end_, то у вектора есть резерв после конца

Таким образом, сложность добавления в начало была бы равна сложности добавления в конец.

Автор: baldina 29.1.2013, 18:00
хитрО  smile 

Автор: bsa 29.1.2013, 19:51
Да ничего хитрого. Оптимизация добавления в конец именно так и сделана. Почему бы не добавить еще и оптимизацию добавления в начало? Не думаю, что еще один указатель сильно много займет ресурсов. А вот выигрыш по скорости добавления в начало был бы ощутимым.

Автор: volatile 29.1.2013, 23:55
Цитата(bsa @  29.1.2013,  19:51 Найти цитируемый пост)
Почему бы не добавить еще и оптимизацию добавления в начало? 

Думаю что вектор не проектировался как контейнер с оптимизацией добавления в конец. Просто это получилось само-собой.
А оптимизация добавления в начало, сама собой не получилась  smile,  ну и делать ее специально никто не стал, так как для этого есть дек.

Если вы считаете что часто нужно такое, можно сделать свой адаптер к вектору (думаю не много кода будет).
Хотя честно, говоря не вижу серьезных причин, почему бы в таком случае, просто не использовать дек...

Автор: mes 30.1.2013, 08:43
Цитата(volatile @  29.1.2013,  22:55 Найти цитируемый пост)
А оптимизация добавления в начало, сама собой не получилась

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

Добавлено через 25 секунд
 smile сам непонял, что сказал...  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)