Должен ли я использовать общий ptr или уникальный ptr

я делал некоторые объекты, используя идиому pimpl, но я не уверен, использовать ли std::shared_ptr или std::unique_ptr.

Я понимаю, что std::unique_ptr более эффективно, но это не столько проблема для меня, так как эти объекты в любом случае относительно тяжеловесны, поэтому стоимость std::shared_ptr над std::unique_ptr относительно незначителен.

в настоящее время я собираюсь с std::shared_ptr просто из-за дополнительной гибкости. Например, используя std::shared_ptr позволяет мне хранить эти объекты в hashmap для быстрого доступа, все еще имея возможность возвращать копии этих объектов вызывающим (поскольку я считаю, что любые итераторы или ссылки могут быстро стать недействительными).

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

это правильно?

4 ответов


Я делал некоторые объекты, используя идиому pimpl, но я не уверен, следует ли использовать shared_ptr или unique_ptr.

наверняка unique_ptr или scoped_ptr.

Pimpl - это не шаблон, а идиома, которая имеет дело с зависимостью от времени компиляции и бинарной совместимостью. Это не должно влиять на семантику объектов, особенно в отношении их поведения копирования.

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

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

это не анти-шаблон, на самом деле, это шаблон: сглаживание. Вы уже используете его на C++ с голыми указателями и ссылками. shared_ptr предложите дополнительную меру "безопасности", чтобы избежать мертвых ссылок, за счет дополнительной сложности и новых проблем (остерегайтесь циклов, которые создают утечки памяти).


не имеет отношения к Pimpl

Я понимаю unique_ptr более эффективен, но это не так много для меня, так как эти объекты относительно тяжеловес в любом случае так стоимость shared_ptr над unique_ptr относительно незначителен.

если вы можете разложить какое-то состояние, вы можете взглянуть на Flyweight узор.


если вы используете shared_ptr, Это не совсем классический pimpl идиома (если вы не предпримете дополнительных шагов). Но настоящий вопрос почему вы хотите использовать умный указатель для начала; это очень ясно, где delete должно произойти, и нет никакой проблемы исключение безопасности или другое, чтобы быть обеспокоены. Максимально, умный указатель сохранит вам строку или две кода. И только один, который имеет правильную семантику boost::scoped_ptr, и я не думаю, что это сработает в данном случае. (IIRC, это требует ля полный тип для создания экземпляра, но я мог бы быть неправильный.)

важным аспектом идиомы pimpl является то, что ее использование должно быть прозрачный для клиента; класс должен вести себя точно так же, как если бы она была реализована классически. Это значит или блокировать копирование и назначение или реализация deep copy, если класс является неизменяемым (без функций-членов non-const). Ничего из обычного интеллектуальные указатели реализуют глубокую копию; вы можете реализовать один из конечно, но это, вероятно, по-прежнему требуется полный тип всякий раз, когда происходит копирование, что означает, что вам все равно придется обеспечить определенный пользователем конструктор копирования и оператор присваивания (поскольку они не могут быть inline). Учитывая это, вероятно, нет стоит потрудиться с помощью smart pointer.

исключение, если объекты являются неизменными. В этом случае не имеет значения, является ли копия глубокой или нет, и shared_ptr полностью справляется с ситуацией.


при использовании shared_ptr (например, в контейнере, затем найдите это и верните его -значение), вы не вызываете копию объекта, на который он указывает, просто копию указателя со счетчиком ссылок.

это означает, что если вы изменяете базовый объект из нескольких точек, то вы влияете на изменения в экземпляр. Это именно то, для чего он предназначен, так что не некоторые анти-шаблон!

при передаче shared_ptr (Как говорят комментарии), лучше пройти по ссылке const и скопировать (там, увеличив количество ссылок), где это необходимо. Что касается возврата, случае.


Да, пожалуйста, используйте их. Проще говоря, shared_ptr-это реализация умного указателя. unique_ptr-это реализация автоматического указателя: