Увеличить функцию shared_ptr use_count - PullRequest
4 голосов
/ 28 мая 2010

Моя проблема с приложением следующая -

У меня большая структура фу. Поскольку они велики и по причинам управления памятью, мы не хотим удалять их, когда обработка данных завершена.

Мы храним их в std::vector<boost::shared_ptr<foo>>.

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

Таким образом, в нашей реализации после завершения обработки мы удаляем все копии boost::shared_ptr<foo>>, за исключением копии в векторе. Это уменьшит счетчик ссылок в shared_ptr до 1. Целесообразно ли использовать shared_ptr.use_count (), чтобы узнать, равен ли он 1, чтобы узнать, когда все другие части моего приложения будут выполнены с данными.

Еще одна причина, по которой я задаю этот вопрос, заключается в том, что документация по поддержке общего указателя shared_ptr рекомендует не использовать "use_count" для рабочего кода.


Редактировать - Я не сказал, что когда нам понадобится новый foo, мы будем сканировать вектор указателей foo в поисках foo, который в данный момент не используется, и использовать этот foo для следующего цикла обработки. Вот почему я подумал, что использование счетчика ссылок 1 будет безопасным способом гарантировать, что данный конкретный объект foo больше не используется.

Ответы [ 5 ]

4 голосов
/ 28 мая 2010

Моя немедленная реакция (и я признаю, что это не более того) звучит так, как будто вы пытаетесь получить эффект какого-то распределителя пула.Возможно, вам лучше перегрузить operator new и operator delete, чтобы получить желаемый эффект чуть более напрямую.С чем-то подобным вы, вероятно, можете просто использовать shared_ptr, как обычно, и другая работа, которую вы хотите отложить, будет обработана в operator delete для этого класса.

Это оставляет более простой вопрос: чтоВы действительно пытаетесь достичь этого?С точки зрения управления памятью, одно общее желание состоит в том, чтобы выделять память для большого количества объектов одновременно, и после того, как весь блок пуст, освободить весь блок сразу.Если вы пытаетесь сделать что-то в этом порядке, это почти наверняка легче сделать, перегружая new и delete, чем играть в игры с shared_ptr s use_count.

Редактировать: на основев вашем комментарии перегрузка new и delete для класса звучит как правильная вещь.Во всяком случае, интеграция в существующий код, вероятно, будет проще;на самом деле, вы часто можете делать это совершенно прозрачно.

Общая идея распределителя в значительной степени такая же, как вы обрисовали в отредактированном вопросе: иметь структуру (растровые изображения и связанные списки являются общими)отслеживать ваши бесплатные объекты.Когда new требуется выделить объект, он может сканировать битовый вектор или просматривать заголовок связанного списка свободных объектов и возвращать его адрес.

Это один случай, когда связанные списки могут работатьдовольно хорошо - вам (как правило) не нужно беспокоиться об использовании памяти, потому что вы храните свои ссылки прямо в свободном объекте, и вам (практически) никогда не придется ходить по списку, потому что, когда вам нужно выделить объект,Вы просто берете первый элемент в списке.

Подобные вещи особенно характерны для небольших объектов, поэтому вы можете захотеть взглянуть на главу Modern C ++ Design , посвященную распределителю небольших объектов.(и с тех пор одна-две статьи Андрея Александреску о его новых идеях о том, как делать такие вещи).Также есть распределитель Boost :: pool, который, по крайней мере, несколько похож.

3 голосов
/ 28 мая 2010

Если вы хотите узнать, является ли счетчик использования 1, используйте функцию-член unique().

2 голосов
/ 28 мая 2010

Я думаю, что вы можете использовать пользовательские функции удаления shared_ptr для вызова определенной функции после выпуска последней копии. Таким образом, вы вообще не используете use_count.

Вам нужно будет хранить что-то, кроме копии shared_ptr в вашем vector, чтобы shared_ptr отслеживал только ожидающую обработку.

В Boost есть несколько примеров пользовательских удалителей в shared_ptr документах.

2 голосов
/ 28 мая 2010

Я бы сказал, что ваше приложение должно иметь какой-то метод, который исключает все ссылки на Foo из других частей приложения, и этот метод следует использовать вместо проверки use_count(). Кроме того, если use_count() больше 1, что сделает ваша программа? Вы не должны полагаться на функции shared_ptr для устранения всех ссылок, ваша архитектура приложения должна быть в состоянии устранить ссылки. В качестве окончательной проверки перед удалением его из вектора вы можете assert(unique()) убедиться, что он действительно выпускается.

0 голосов
/ 28 мая 2010

Я бы предложил, чтобы вместо попытки использовать use_count для shared_ptr для отслеживания, было бы лучше реализовать собственный счетчик использования. таким образом, вы будете иметь полный контроль над этим, а не использовать shared_ptr, который, как вы правильно предполагаете, не рекомендуется. Вы также можете предварительно установить свой собственный счетчик, чтобы учесть количество потоков, которое, по вашему мнению, должно будет воздействовать на данные, а не полагаться на то, что все они инициализируются в начале для получения своих копий структуры.

...