Страницы

Поиск по вопросам

четверг, 18 октября 2018 г.

Хранение одного экземпляра класса в нескольких массивах

У меня имеется класс "рассказ", который нужно хранить в различных сборниках. Суть в том, что я использую указатели, т.е.
class Story { ... }
class Compilation { ... vector stories; ... }
Необходимо изменять информацию о рассказах. Здесь всё ясно, поскольку мы храним указатели, то всё будет меняться параллельно. Удаление из конкретного сборника тоже ясно. Но если окажется, что этот сборник - последний, где хранится наш рассказ, то как произвести удаление без утечки памяти? Если же мы хотим удалить рассказ навсегда, то как его удалить из всех сборников сразу?
Хранить сборники внутри рассказа тоже не вариант, так как необходимо устраивать поиск по сборникам, количеству рассказов в них и т.д.


Ответ

Вам нужно пользоваться shared_ptr вместо сырого указателя. При этом ваш объект будет удалён только когда последний указатель на него умрёт.
Вот небольшой пример работы с ним
#include #include #include using namespace std;
class Story { int n; public: Story(int n): n(n) { cout << "story #" << n << " created" << endl; } ~Story() { cout << "story #" << n << " destroyed" << endl; } };
int main() { vector> list1, list2;
cout << "creating #1 and adding to first list" << endl; list1.emplace_back(make_shared(1)); cout << "copying #1 to second list" << endl; list2.push_back(list1[0]); cout << "creating #2" << endl; auto story2 = make_shared(2); cout << "adding #2 to the second list" << endl; list2.push_back(story2); cout << "removing first ptr to story #2" << endl; story2 = nullptr; cout << "removing second ptr to story #2, now it will be destroyed" << endl; list2.resize(1); cout << "clearing first list" << endl; list1.clear(); cout << "clearing second list, now story #1 will be destroyed" << endl; list2.clear(); cout << "done" << endl; }
Вывод:
creating #1 and adding to first list story #1 created copying #1 to second list creating #2 story #2 created adding #2 to the second list removing first ptr to story #2 removing second ptr to story #2, now it will be destroyed story #2 destroyed clearing first list clearing second list, now story #1 will be destroyed story #1 destroyed done

Как правильно подсказывает @ixSci в комментариях, вы таки можете удалить элемент полностью во всех списках, если примете немного другой дизайн. Поделим списки на владеющие своими элементами (эти списки будут содержать shared_ptr), и невладеющие (эти списки будут содержать weak_ptr, невладеющий указатель). Тогда когда все сильные ссылки (shared_ptr) на объект умрут, слабые (weak_ptr) тоже станут недействительны.
Этот оформляется так
#include #include #include #include using namespace std;
class Story { int n; public: Story(int n): n(n) { cout << "story #" << n << " created" << endl; } ~Story() { cout << "story #" << n << " destroyed" << endl; } void print() { cout << "story #" << n << " reporting" << endl; } };
int main() { vector> main_list; vector> aux_list;
cout << "creating and adding to owning list" << endl; main_list.emplace_back(make_shared(1)); main_list.emplace_back(make_shared(2)); cout << "copying to non-owning list" << endl; aux_list.push_back(main_list[0]); aux_list.push_back(main_list[1]); cout << "removing #2" << endl; main_list.resize(1); for (auto& weakptr : aux_list) { if (auto strongptr = weakptr.lock()) strongptr->print(); else cout << "(deleted entry)" << endl; } cout << "cleaning non-owning list" << endl; aux_list.erase( remove_if(begin(aux_list), end(aux_list), [](auto wp) { return wp.expired(); }), end(aux_list)); for (auto& weakptr : aux_list) { if (auto strongptr = weakptr.lock()) strongptr->print(); else cout << "(cannot happen)" << endl; } cout << "done" << endl; }
Вывод:
creating and adding to owning list story #1 created story #2 created copying to non-owning list removing #2 story #2 destroyed story #1 reporting (deleted entry) cleaning non-owning list story #1 reporting done story #1 destroyed

Комментариев нет:

Отправить комментарий