Когда бы вы использовали std :: auto_ptr вместо boost :: shared_ptr?
-
22-07-2019 - |
Вопрос
Мы в значительной степени перешли на использование boost :: shared_ptr
во всем нашем коде, однако у нас все еще есть отдельные случаи, когда мы используем std :: auto_ptr
, включая синглтон-классы:
template < typename TYPE >
class SharedSingleton
{
public:
static TYPE& Instance()
{
if (_ptrInstance.get() == NULL)
_ptrInstance.reset(new TYPE);
return *_ptrInstance;
}
protected:
SharedSingleton() {};
private:
static std::auto_ptr < TYPE > _ptrInstance;
};
Мне сказали, что есть очень веская причина, почему это не было сделано shared_ptr
, но я не понимаю почему? Я знаю, что auto_ptr
в конечном итоге будет помечен как устаревший в следующем стандарте, поэтому я хотел бы узнать, что / как я могу заменить этой реализацией .
Кроме того, есть ли другие причины, по которым вы решили бы использовать auto_ptr
вместо shared_ptr
? И видите ли вы какие-либо проблемы? переходить на shared_ptr в будущем?
Изменить.
<Ол> auto_ptr
на shared_ptr
в приведенном выше коде "", ответ будет положительным - однако я получу небольшой удар по производительности . auto_ptr
в конечном итоге помечается как устаревший, и мы переходим к std :: shared_ptr
, нам необходимо тщательно протестировать наш код, чтобы убедиться в его соблюдении. различной семантикой владения. Решение
auto_ptr
и shared_ptr
решают совершенно разные проблемы. Одно не заменяет другое.
auto_ptr
- это тонкая оболочка вокруг указателей для реализации семантики RAII , так что ресурсы всегда высвобождаются, даже когда возникают исключения. auto_ptr
не выполняет никакого подсчета ссылок или чего-либо подобного, он не заставляет несколько указателей указывать на один и тот же объект при создании копий. На самом деле, это очень разные. auto_ptr
- один из немногих классов, где оператор присваивания изменяет объект source . Рассмотрите этот бесстыдный плагин со страницы auto_ptr википедии :
int *i = new int;
auto_ptr<int> x(i);
auto_ptr<int> y;
y = x;
cout << x.get() << endl; // Print NULL
cout << y.get() << endl; // Print non-NULL address i
Обратите внимание, как выполняется
y = x;
изменяет не только y, но и x.
Шаблон boost :: shared_ptr
позволяет легко обрабатывать несколько указателей на один и тот же объект, и объект удаляется только после того, как последняя ссылка на него вышла из области видимости. Эта функция бесполезна в вашем сценарии, который (пытается) реализовать Singleton . В вашем сценарии всегда есть 0 ссылок на 1 ссылку на единственный объект класса, если таковой имеется.
По сути, объекты auto_ptr
и объекты shared_ptr
имеют совершенно разную семантику (поэтому вы не можете использовать первое в контейнерах, но с последним это нормально), и я надеюсь, что у вас есть хорошие тесты для отслеживания любых регрессий, которые вы ввели при переносе кода. : -} р>
Другие советы
Другие ответили, почему этот код использует auto_ptr
вместо shared_ptr
. Чтобы ответить на другие ваши вопросы:
Чем / как я могу заменить эту реализацию?
Используйте boost :: scoped_ptr
или unique_ptr
(доступно как в Boost, так и в новом стандарте C ++). И scoped_ptr
, и unique_ptr
обеспечивают строгое владение (и не требуют подсчета ссылок), и они избегают удивительной семантики удаления-при-копировании auto_ptr
. р>
Кроме того, есть ли другие причины, по которым вы решили бы использовать auto_ptr
вместо shared_ptr
? И видите ли вы какие-либо проблемы с переходом на shared_ptr
в будущем?
Лично я бы не стал использовать auto_ptr
. Удалить при копировании слишком не интуитивно понятно. Херб Саттер, похоже, согласен . Переключение на scoped_ptr
, unique_ptr
или shared_ptr
не должно вызывать проблем. В частности, shared_ptr
должен быть заменой, если вас не волнует подсчет ссылок. scoped_ptr
является заменой, если вы не используете возможности передачи кода auto_ptr
. Если вы используете передачу права собственности, то unique_ptr
является почти заменой, за исключением того, что вместо этого вам нужно явно вызвать move
для передачи права собственности. См. здесь для примера.
auto_ptr - единственный вид интеллектуального указателя, который я использую. Я использую его, потому что я не использую Boost, и потому что я обычно предпочитаю, чтобы мои бизнес / прикладные классы явно определить семантику и порядок удаления, а не зависеть от коллекции или отдельные умные указатели.