Следует ли хранить объекты целиком или указатели на объекты в контейнерах?

Разработка новой системы с нуля. Я буду использовать STL для хранения списков и карт некоторых долгоживущих объектов.

Вопрос: Должен ли я гарантировать, что мои объекты имеют конструкторы копирования и хранят копии объектов в моих контейнерах STL, или, как правило, лучше самому управлять жизненным циклом и областью действия и просто хранить указатели на эти объекты в моих контейнерах STL?

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

Два очевидных недостатка игры с указателями: 1) Я должен сам управлять выделением / освобождением этих объектов за пределами STL. 2) Я не могу создать временный объект в стеке и добавить его в свои контейнеры.

Что еще мне не хватает?

Боже, мне нравится этот сайт, это ТОЧНЫЙ вопрос, о котором я думал сегодня ... спасибо, что выполнили задание, задавая его для меня :-)

eviljack 30.01.2009 17:19

еще одна интересная вещь заключается в том, что мы должны проверить, действительно ли указатель был добавлен в коллекцию, и если это не так, нам, вероятно, следует вызвать delete, чтобы избежать утечек памяти ... if ((set.insert (pointer)). second = false) {удалить указатель;}

Oleg Vazhnev 11.03.2011 22:15
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
163
2
64 222
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

Если вы храните полиморфные объекты, вам всегда нужно использовать набор указателей базовых классов.

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

Я любил режущего демона!

idichekop 08.06.2017 23:55

Кажется, вы хорошо понимаете разницу. Если предметы небольшие и их легко скопировать, то непременно сохраните их.

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

@ Торбьорн хорошо разбирается в нарезке.

Да, и никогдаКогда-либоКогда-либо создает коллекцию auto_ptr

Torbjörn Gyllebring 26.09.2008 23:15

Правильно, auto_ptr не является умным указателем - он не подсчитывает ссылки.

Lou Franco 26.09.2008 23:17

auto_ptr также не имеет семантики неразрушающего копирования. Акт назначения auto_ptr от one к another освободит ссылку от one и изменит one.

Andy Finkenstadt 27.10.2011 20:55

Использование указателей будет более эффективным, поскольку контейнеры будут копировать только указатели, а не полные объекты.

Здесь есть полезная информация о контейнерах STL и интеллектуальных указателях:

Почему неправильно использовать std :: auto_ptr <> со стандартными контейнерами?

Почему бы не получить лучшее из обоих миров: создать контейнер интеллектуальных указателей (например, boost::shared_ptr или std::shared_ptr). Вам не нужно управлять памятью, и вам не нужно иметь дело с операциями с большими копиями.

Чем этот подход отличается от того, что предложил Ник Хаддад, используя библиотеку контейнеров Boost Pointer?

Thorsten Schöning 06.01.2016 11:58

@ ThorstenSchöning std :: shared_ptr не добавляет зависимости от ускорения.

James Johnston 25.01.2016 20:50

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

auserdude 02.08.2018 00:26

Как правило, лучше всего хранить объекты непосредственно в контейнере STL, так как это самый простой, наиболее эффективный и легкий в использовании объект.

Если сам ваш объект имеет не копируемый синтаксис или является абстрактным базовым типом, вам нужно будет хранить указатели (проще всего использовать shared_ptr)

Это не наиболее эффективно, если ваши объекты большие и вы часто перемещаете элементы.

allyourcode 25.05.2013 06:24
Ответ принят как подходящий

Поскольку люди вмешиваются в эффективность использования указателей.

Если вы планируете использовать std :: vector, и если обновлений мало, и вы часто перебираете свою коллекцию, и это неполиморфный тип, хранение «копий» объекта будет более эффективным, поскольку вы получите лучшую локальность ссылки.

Otoh, если обновления являются обычными, указатели хранения сэкономят затраты на копирование / перемещение.

С точки зрения локальности кеша, хранение указателей в векторе может быть эффективным, если используется вместе с настраиваемым распределителем для указателей. Пользовательский распределитель должен позаботиться о расположении кеша, например, используя новое размещение (см. en.wikipedia.org/wiki/Placement_syntax#Custom_allocators).

amit 27.02.2011 14:34

Это действительно зависит от вашей ситуации.

Если ваши объекты небольшие, а создание копии объекта является легковесным, то хранение данных внутри контейнера stl, на мой взгляд, проще и проще в управлении, потому что вам не нужно беспокоиться об управлении временем жизни.

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

Если вы решили использовать указатели на объекты, взгляните на Библиотека контейнеров Boost Pointer. Эта библиотека ускорения обертывает все контейнеры STL для использования с динамически выделяемыми объектами.

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

class BigExpensive { ... }

// create a pointer vector
ptr_vector<BigExpensive> bigVector;
bigVector.push_back( new BigExpensive( "Lexus", 57700 ) );
bigVector.push_back( new BigExpensive( "House", 15000000 );

// get a reference to the first element
MyClass& expensiveItem = bigList[0];
expensiveItem.sell();

Эти классы обертывают контейнеры STL и работают со всеми алгоритмами STL, что действительно удобно.

Также существуют средства для передачи права собственности на указатель в контейнере вызывающей стороне (через функцию выпуска в большинстве контейнеров).

Если объекты должны быть упомянуты в другом месте кода, сохраните в векторе boost :: shared_ptr. Это гарантирует, что указатели на объект останутся действительными, если вы измените размер вектора.

Т.е.:

std::vector<boost::shared_ptr<protocol> > protocols;
...
connection c(protocols[0].get()); // pointer to protocol stays valid even if resized

Если больше никто не хранит указатели на объекты, или список не растет и не сжимается, просто сохраните как обычные старые объекты:

std::vector<protocol> protocols;
connection c(protocols[0]); // value-semantics, takes a copy of the protocol

Извините, что прыгнул через 3 года после события, но предостережение ...

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

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

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

Технические характеристики никогда не высечены из камня. Я не думаю, что это означает, что вам следует использовать исключительно контейнеры-указатели, хотя контейнеры-указатели Boost, похоже, делают этот вариант намного более привлекательным. Я скептически отношусь к тому, что вам нужно полностью пересмотреть всю программу сразу, если вы решите, что контейнер объекта должен быть преобразован в контейнер указателя. Это может быть так в некоторых дизайнах. В таком случае это хрупкая конструкция. В таком случае не вините свою проблему в «слабости» контейнеров объектов.

allyourcode 25.05.2013 06:22

Вы могли бы оставить элемент в векторе с семантикой значения и выполнить внутри полиморфное поведение.

Billy ONeal 19.07.2013 05:42

Этот вопрос уже давно меня беспокоит.

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

Самый важный момент в этом посте - проверь это сам, используя ваши объекты

Я сделал это сегодня, чтобы 500 раз проверить скорость вызова функции-члена для коллекции из 10 миллионов объектов.

Функция обновляет x и y на основе xdir и ydir (всех переменных-членов с плавающей запятой).

Я использовал std :: list для хранения обоих типов объектов и обнаружил, что сохранение объекта в списке немного быстрее, чем использование указателя. С другой стороны, производительность была очень близкой, поэтому все сводится к тому, как они будут использоваться в вашем приложении.

Для справки, с -O3 на моем оборудовании указатели заняли 41 секунду, а необработанные объекты - 30 секунд.

Другие вопросы по теме