Использует std::vector <std:: shared_ptr <const T>> антипаттерн?
Долгое время я использовал std::vector
и std::shared_ptr
рука об руку. Недавно я начал использовать std::shared_ptr<const T>
всякий раз, когда нужен указатель на объект const. Все в порядке, так как std::shared_ptr<T>
можно отнести к std::shared_ptr<const T>
, а затем они используют один и тот же счетчик ссылок, и все кажется естественным.
Но когда я пытаюсь использовать конструкции, такие как std::vector< std::shared_ptr<const T> >
, я сталкиваюсь с проблемами. Для упрощения я буду обозначать две структуры:
template <class T>
using SharedPtrVector = std::vector< std::shared_ptr<T> >;
template <class T>
using SharedConstPtrVector = std::vector< std::shared_ptr<const T> >;
Проблема заключается в том, что хотя SharedPtrVector
и SharedConstPtrVector
очень похожи, SharedConstPtrVector
нельзя отнести к SharedPtrVector
.
Поэтому каждый раз, когда я хочу быть константой корректно и записываю такую функцию, как:
void f(const SharedConstPtrVector<T>& vec);
я не могу передать const SharedPtrVector<T>
в f
.
Я много думал об этом и рассматривал несколько альтернатив:
-
Запись функций преобразования
template <typename T>
SharedConstPtrVector<T> toConst(const SharedPtrVector<T>&);
-
Введите код в общей форме:
template <typename T>
void f(const std::vector< std::shared_ptr<T> >& vec);
или
template <typename TIterator>
void f(TIterator begin, TIterator end);
-
Отбросить идею std::vector< std::shared_ptr<const T> >
Проблема с 1. - это вычислительные накладные расходы и повышенная уродство кода, а 2. дает код "все является шаблоном".
Я неопытный программист, и я не хочу идти в неправильном направлении. Я хотел бы услышать совет от кого-то, у кого есть опыт в этой проблеме.
Ответы
Ответ 1
Я бы предложил рассмотреть ваш дизайн с целью установить четкого владельца этого объекта. Это отсутствие четкой собственности, которая заставляет людей использовать общие умные указатели.
Bjarne Stroustrup рекомендует использовать интеллектуальные указатели только в крайнем случае. Его рекомендации (от самого лучшего к худшему):
- Сохранять объект по значению.
- Хранить многие объекты в контейнере по значению.
- Если ничего не работает, используйте интеллектуальные указатели.
См. Bjarne Stroustrup - Суть С++: с примерами в С++ 84, С++ 98, С++ 11 и С++ 14 в 0:37:40.
Ответ 2
1 Проблема не связана с shared_ptr<>
, но встречается уже для обычных указателей:
template<typename T>
void foo(std::vector<const T*>);
int a,b;
std::vector<int*> bar={&a,&b};
foo<???>(bar); // no value for ??? works
2 Конструкция vector<shared_ptr<T>>
разумно только в том случае, если у владельца нет владельца.
Ответ 3
Это допустимый способ хранения неизменяемых (и, следовательно, потокобезопасных) объектов, строительного блока для кеша для копирования по одной записи. Определенно не анти-шаблон.
Ответ 4
если вы настаиваете на сохранении std::vector
, вы можете попытаться инкапсулировать его в структуру идиомы дескриптора.
это позволяет сохранить общий указатель не const
в дескрипторе const
.