Разработка новой системы с нуля. Я буду использовать STL для хранения списков и карт некоторых долгоживущих объектов.
Вопрос: Должен ли я гарантировать, что мои объекты имеют конструкторы копирования и хранят копии объектов в моих контейнерах STL, или, как правило, лучше самому управлять жизненным циклом и областью действия и просто хранить указатели на эти объекты в моих контейнерах STL?
Я понимаю, что подробностей здесь немного, но я ищу "теоретический" лучший ответ, если он существует, поскольку я знаю, что оба этих решения возможны.
Два очевидных недостатка игры с указателями: 1) Я должен сам управлять выделением / освобождением этих объектов за пределами STL. 2) Я не могу создать временный объект в стеке и добавить его в свои контейнеры.
Что еще мне не хватает?
еще одна интересная вещь заключается в том, что мы должны проверить, действительно ли указатель был добавлен в коллекцию, и если это не так, нам, вероятно, следует вызвать delete, чтобы избежать утечек памяти ... if ((set.insert (pointer)). second = false) {удалить указатель;}





Если вы храните полиморфные объекты, вам всегда нужно использовать набор указателей базовых классов.
То есть, если вы планируете хранить различные производные типы в своей коллекции, вы должны хранить указатели, иначе вы будете съедены нарезкой демона.
Я любил режущего демона!
Кажется, вы хорошо понимаете разницу. Если предметы небольшие и их легко скопировать, то непременно сохраните их.
Если нет, я бы подумал о хранении интеллектуальных указателей (не auto_ptr, интеллектуального указателя с подсчетом ссылок) на те, которые вы размещаете в куче. Очевидно, что если вы выберете интеллектуальные указатели, вы не сможете хранить объекты, выделенные временным стеком (как вы сказали).
@ Торбьорн хорошо разбирается в нарезке.
Да, и никогдаКогда-либоКогда-либо создает коллекцию auto_ptr
Правильно, auto_ptr не является умным указателем - он не подсчитывает ссылки.
auto_ptr также не имеет семантики неразрушающего копирования. Акт назначения auto_ptr от one к another освободит ссылку от one и изменит one.
Использование указателей будет более эффективным, поскольку контейнеры будут копировать только указатели, а не полные объекты.
Здесь есть полезная информация о контейнерах STL и интеллектуальных указателях:
Почему неправильно использовать std :: auto_ptr <> со стандартными контейнерами?
Почему бы не получить лучшее из обоих миров: создать контейнер интеллектуальных указателей (например, boost::shared_ptr или std::shared_ptr). Вам не нужно управлять памятью, и вам не нужно иметь дело с операциями с большими копиями.
Чем этот подход отличается от того, что предложил Ник Хаддад, используя библиотеку контейнеров Boost Pointer?
@ ThorstenSchöning std :: shared_ptr не добавляет зависимости от ускорения.
Вы не можете использовать общие указатели для обработки вашего полиморфизма, поэтому вы в конечном итоге пропустите эту функцию при таком подходе, если вы явно не укажете указатели
Как правило, лучше всего хранить объекты непосредственно в контейнере STL, так как это самый простой, наиболее эффективный и легкий в использовании объект.
Если сам ваш объект имеет не копируемый синтаксис или является абстрактным базовым типом, вам нужно будет хранить указатели (проще всего использовать shared_ptr)
Это не наиболее эффективно, если ваши объекты большие и вы часто перемещаете элементы.
Поскольку люди вмешиваются в эффективность использования указателей.
Если вы планируете использовать std :: vector, и если обновлений мало, и вы часто перебираете свою коллекцию, и это неполиморфный тип, хранение «копий» объекта будет более эффективным, поскольку вы получите лучшую локальность ссылки.
Otoh, если обновления являются обычными, указатели хранения сэкономят затраты на копирование / перемещение.
С точки зрения локальности кеша, хранение указателей в векторе может быть эффективным, если используется вместе с настраиваемым распределителем для указателей. Пользовательский распределитель должен позаботиться о расположении кеша, например, используя новое размещение (см. en.wikipedia.org/wiki/Placement_syntax#Custom_allocators).
Это действительно зависит от вашей ситуации.
Если ваши объекты небольшие, а создание копии объекта является легковесным, то хранение данных внутри контейнера 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, похоже, делают этот вариант намного более привлекательным. Я скептически отношусь к тому, что вам нужно полностью пересмотреть всю программу сразу, если вы решите, что контейнер объекта должен быть преобразован в контейнер указателя. Это может быть так в некоторых дизайнах. В таком случае это хрупкая конструкция. В таком случае не вините свою проблему в «слабости» контейнеров объектов.
Вы могли бы оставить элемент в векторе с семантикой значения и выполнить внутри полиморфное поведение.
Этот вопрос уже давно меня беспокоит.
Я склоняюсь к хранению указателей, но у меня есть некоторые дополнительные требования (оболочки SWIG lua), которые могут не относиться к вам.
Самый важный момент в этом посте - проверь это сам, используя ваши объекты
Я сделал это сегодня, чтобы 500 раз проверить скорость вызова функции-члена для коллекции из 10 миллионов объектов.
Функция обновляет x и y на основе xdir и ydir (всех переменных-членов с плавающей запятой).
Я использовал std :: list для хранения обоих типов объектов и обнаружил, что сохранение объекта в списке немного быстрее, чем использование указателя. С другой стороны, производительность была очень близкой, поэтому все сводится к тому, как они будут использоваться в вашем приложении.
Для справки, с -O3 на моем оборудовании указатели заняли 41 секунду, а необработанные объекты - 30 секунд.
Боже, мне нравится этот сайт, это ТОЧНЫЙ вопрос, о котором я думал сегодня ... спасибо, что выполнили задание, задавая его для меня :-)