возвращает «указатель», который должен удерживаться умным указателем - PullRequest
9 голосов
/ 10 марта 2009

У меня есть проект, в котором я хотел бы больше использовать умные указатели. В целом, я был успешен в этой цели. Однако я столкнулся с одной вещью, в которой я не уверен, что такое «лучшая практика».

По сути, я хотел бы вернуть «указатель» из функции, но требует , чтобы пользователь удерживал его в интеллектуальном указателе. Более того, я не хочу указывать конкретный умный указатель (общий или ограниченный).

Проблема в основном в том, что, похоже, нет правильного способа повысить scoped_ptr до shared_ptr (я думаю, это было бы идеальным решением). Я понимаю, почему они этого не сделали, поскольку это позволило бы передать право собственности, что может привести к некоторым проблемам, таким как std::auto_ptr.

Однако передача права собственности кажется хорошей идеей для этого дела. Итак, моя идея такова:

// contrived example of factory pattern
std::auto_ptr<A> func() { return std::auto_ptr<A>(new A); }

Это работает "хорошо", так как и scoped_ptr, и shared_ptr имеют конструкторы, которые берут в собственность std::auto_ptr.

Итак, мой вопрос: это хорошая практика? Есть ли лучшее решение? Единственная реальная альтернатива, которую я смог придумать, - это использовать шаблон шаблона в качестве возвращаемого значения, например:

// similar to above example
template <template <typename> class P>
P<A> func() { return P<A>(new A); }

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

Мысли

Ответы [ 3 ]

11 голосов
/ 10 марта 2009

Использование std::auto_ptr является хорошей практикой, фактически был предложен такой пример Бьярн Страуструп.

Семантика перемещения auto_ptr дает вам правильные инструменты для ее решения.

Например:

auto_ptr<Foo> make_foo()
{
    return auto_ptr<Foo>(new Foo);
}

Foo *raw_pointer=make_foo().release();
shared_ptr<Foo> shared_pointer=make_foo();
auto_ptr<Foo> auto_pointer=make_foo();

Если вы вернете shared_ptr, вы не сможете вернуться к обычному указателю, с auto_ptr вы можете. Вы всегда можете обновить auto_ptr до общего, но не другого направления.

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

P.S .: scoped_ptr это просто версия auto_ptr для бедных - она ​​не копируется и делает не имеет конструктора по умолчанию. Это больше похоже на «менее запутанную» версию auto_ptr, по сравнению с shared_ptr она не в tr1. Вообще нет особых преимуществ использования scoped_ptr свыше auto_ptr

3 голосов
/ 10 марта 2009

Если вы строите фабрику, это нормально, вы просто возвращаете указатель. И пользователь вашей фабрики может сам принять решение, как и куда поставить этот указатель.
Если вам нужно принудительно использовать умный указатель, вы должны ограничить выбор, так как вы не хотите, чтобы они использовали «неправильные».
Так что boost :: shared_ptr. Но лучше определить его, чем MyClassPtr или MyClass :: ptr.
Все-таки заводы у них как бы «новые». Когда я хочу, я помещаю результат new внутри std :: auto_ptr. Но я не хочу, чтобы меня заставляли вызывать «релиз», когда мне не нужен умный указатель.

1 голос
/ 18 октября 2011

С C ++ 11 вы сможете использовать std::unique_ptr, так как другие умные типы указателей имеют конструкторы, которые принимают std::unique_ptr. Если вы ведете внутренний список таких ресурсов, вы, вероятно, захотите использовать std::shared_ptr.

...