![]() |
Модераторы: Daevaorn |
![]() ![]() ![]() |
|
mr.DUDA |
|
||||||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 25 Всего: 232 |
Если хранить сами объекты, то будет проблема с:
т.к. при добавлении объекта в список будет использован конструктор копирования, и существующий пойнтер просто скопируется в новый объект. А если делать так, как нам советуют в руководстве по STL:
то в этом примере получим утечку памяти. Всё в том же руководстве по STL (Степанов, Менг Ли) есть пример как чистить память алгоритмом "release" (примеры release1 и release2):
Но никакой шаблонной ф-ции "release" в STL нету !!! А каждый раз чистить весь контейнер циклом в деструкторе - неудобно и громоздко. Помогите люди добрые, как же правильно хранить объекты в контейнере ? ![]() -------------------- ![]() |
||||||
|
|||||||
Nastya |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1287 Регистрация: 27.3.2002 Где: Мариуполь Репутация: 5 Всего: 44 |
А если создавать свой класс сразу со всеми кострукторвами, дистукторами, конструкаторами копирования и перегрузками оперраторов такизх как = и т.д.
Или такой вариант совсем не подходит? -------------------- Что бы понять рекурсию, надо понять рекурсию "Профессионал - это человек сделавший все возможные ошибки в очень узкой области". Н.Бор |
|||
|
||||
mr.DUDA |
|
|||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 25 Всего: 232 |
Подходит вроде, только я до сих пор не могу понять: что же надо перегружать -- оператор "=", конструктор копирования, или и то и другое ? Если и то и другое, то покатит ли такой вариант:
Я так раньше делал, чтобы не писать по 2 раза один и тот же код копирования. -------------------- ![]() |
|||
|
||||
mr.DUDA |
|
|||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 25 Всего: 232 |
Нашел выход:
Это один умный чел написал. Так легче, чем писать операторы "=", по сто раз переприсваивать значения объектам и пр. ![]() Это сообщение отредактировал(а) mr.DUDA - 21.8.2003, 18:16 -------------------- ![]() |
|||
|
||||
RAN |
|
|||
Опытный ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 709 Регистрация: 14.3.2003 Где: Щёлково Моск.обл. Репутация: 5 Всего: 6 |
Будь осторожен. Надо не забывать удалять объект перед удалением элемента.
У меня вообще есть класс, у которого одно из полей - динамически создаваемый объект. class CClass { private: int x1; int x2; CSomeObject *obj; ......................... и т.д. ......................... }; Проблемы я предвидел, но без ошибок всё равно не обошлось. Всё это у меня в vector помещается. А, как известно, vector неразрывно хранит в памяти элементы. Чтоб это обеспечить он использует оператор =. Мне пришлось реализовывать этот оператор. В нём приходится создавать копию динамического объекта. Короче, очень не эффективно. Я считаю, что это слабое место STL. Для хранения классов с динамическими объектами внутри лучше писать свой контейнер, учитывающий особенности класса. |
|||
|
||||
mr.DUDA |
|
|||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 25 Всего: 232 |
RAN, почему же. Если в деструкторе объекта X, содержащего указатель pY на объект Y, вызывать "delete pY", то какие могут быть проблемы и ошибки. А то, что объект хранится в vector'е, еще не обязывает реализовывать оператор "=" (вообще-то не только для вектора, но и для списка, словаря и т.п. нужно в свой объект поместить конструктор копирования, как я выяснил-таки).
Речь же идет о том, выгоднее ли хранить в контейнере не объекты, а указатели на (существующие) объекты, и что с этим сопряжено (необходимость вручную вызывать деструктор и освобождать память для каждого указателя в контейнере, перед уничтожением самого контейнера). Я предложил пользоваться довольно простыми алгоритмами "map_delete" и "sequence_delete", второй из которых подходит для векторов, списков и deques, а первый - для всех ассоциативных контейнеров. -------------------- ![]() |
|||
|
||||
RAN |
|
||||
Опытный ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 709 Регистрация: 14.3.2003 Где: Щёлково Моск.обл. Репутация: 5 Всего: 6 |
Test that:
Надпись Вот вам и ошибка я, правда, так и не увидел. В debug выскакивает assert, а в релизе WinXP предлагает отправить отчёт в MicroSoft. В полне возможно, что в вашей реализации STL это будет работать, тогда замените везде слово list на vector и ошибка обязательно возникет ![]() А вот лекарство, добавьте в определение класса это:
И всё заработает. ЗАДАНИЕ ![]() |
||||
|
|||||
mr.DUDA |
|
||||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 25 Всего: 232 |
в итераторе вставки элемента в контейнер используется следующий порядок выделения памяти под новый элемент:
Если не задать конструктор копирования в своём классе, то ошибка появится в том случае, если:
Вот и всё. Определив, наконец, конструктор копирования, избавимся от проблем "левых" указателей. Ещё раз подчеркну, что подобные проблемы отсутствуют при хранении в контейнере не объектов, а указателей на объекты (для указателя не нужно определять конструктор копирования, правда ?) -------------------- ![]() |
||||
|
|||||
RAN |
|
||||||
Опытный ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 709 Регистрация: 14.3.2003 Где: Щёлково Моск.обл. Репутация: 5 Всего: 6 |
Всё верно. Пять баллов. Я это написал в ответ на:
Сразу скажу, что insert вызывется и при вызове push_back. Так что использование любого метода для добавления элементов приведён к ошибке.
ПРАВДА. Но надо быть осторожным ![]() |
||||||
|
|||||||
mr.DUDA |
|
|||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 25 Всего: 232 |
Если хранить в контейнере указатели на объекты, сама логика исходников меняется в лучшую сторону (приходится самостоятельно отслеживать ситуации, когда объект создается, копируется и уничтожатеся).
Это добавляет ответственности, зато намного снижает количество ошибок. -------------------- ![]() |
|||
|
||||
RAN |
|
|||
Опытный ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 709 Регистрация: 14.3.2003 Где: Щёлково Моск.обл. Репутация: 5 Всего: 6 |
А вот с этим не согласен. Меняется всё в худшую сторону. Потому как самому лучше ничего не отслеживать - это потенциальный источник ошибки. Всегда, когда это возможно, объкты надо уничтожать в деструкторе, а создавать в конструкторе, или создавать в начале какого-то блока, а уничтожать в его конце. Хранение указателей в контейнере оправдано тогда, когда объекты разных классов далжны храниться в одном контейнере или не известно какого класса объекты будут храниться (у меня второй случай).
Если хранить в контейнере указатели, то это увеличивает расход памяти, сильно увеличивает возможность run-time ошибок, которые могут неожиданно проявить себя в готовом и уже проданном проекты (потом в запарке без сна будешь править, у людей ведь работа стоит). При всём при этом выигрышь в скорости будет не значителен, потому что память будет выделяться под хранение указателей и эти указатели будут также перемещаться с одного места на другой. Это на мой взгляд - проблема STL. |
|||
|
||||
Fantasist |
|
||||
![]() Лентяй ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1517 Регистрация: 24.3.2002 Репутация: 4 Всего: 41 |
Хранить указатели в контейнерах неудобно, потому как надо самому выделять и удалять память. Например твой sequence_delete удаляет объекты из контейнера, но ничего не делает с самим контейнером - получаешь контейнер с инвалидными указателями. Если ты скопируешь указатели в другой контейнер, то непонятно, кто их должен удалять. Отлавливать подобные ошибки очень неприятно. Однако действительно существуют задачи, когда один и тот же объект нужно хранить в нескольких контейнерах и причем создание копии объекта недопустимо, так как он связан с другими объектами. В этом случае на помощь приходят умные указатели в различных вариантах. Например master pointer:
Eдинственное требование от T - конструкрот копирования. В принципе его можно поменять на operator=(). Использование элементарно. Определяется контейнер, который будет "мастером" для объектов. То есть который их будет хранить и удалять.
Конечно, для частых реаллокаций это не очень эффективно. Но частые реаллокации будут возникать, если часто вставлять/удалять элементы чего-нибудь типа vector. Ежели использовать list или map, то реаллокаций не будет. Для вектора, пожалуй, подойдет нечто типа auto_ptr<>. Но если у тебя только один контейнер, то очень реккомендую просто определить конструктор копирования и не мучаться более. Это будет гораздо безопаснее и понятнее. На эту тему много можно поизобретать в зависимости от задачи. Очень большую роль играет выбор контейнера. Подходы для vector, list и map могут весьма отличаться. -------------------- Волны гасят ветер... |
||||
|
|||||
Fantasist |
|
|||
![]() Лентяй ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1517 Регистрация: 24.3.2002 Репутация: 4 Всего: 41 |
И это называется улучшением логики!!! Работал я над кодом с такой логикой - в нем же что-то менять страшно: не понятно где и как это может откликнуться. -------------------- Волны гасят ветер... |
|||
|
||||
mr.DUDA |
|
|||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 25 Всего: 232 |
Хех, наконец-то народ откликнулся
![]() Я для этого и назвал топик "как правильно хранить ?", чтобы узнать, как кто делает ![]() ![]() Выводы однозначные: безопаснее хранить сами объекты, чем указатели. Для хранения объекта класса X нужно определить конструктор копирования для X и переопределить оператор "=". В отдельных случаях, когда необходим полный контроль над "жизненным циклом" объекта, или нужно минимизировать количество реаллокаций, можно допустить хранение пойнтеров вместо объектов. -------------------- ![]() |
|||
|
||||
![]() ![]() ![]() |
Правила форума "С++:Общие вопросы" | |
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |