Является ли возвращение необработанного указателя вместо unique_ptr хорошей практикой кодирования? - PullRequest
0 голосов
/ 31 января 2019

Я изучал unique_ptr и решил написать простой код, чтобы убедиться, что я понял концепцию и то, как ее использовать.Ниже приведен класс Manager, в котором есть deque, который содержит unique_ptrs.

  class BaseClass
 {
    //...
 };

class Manager
{

public:

    std::list<BaseClass*> TempFuncName(Random Parameter)
    {
        std::list<BaseClass*> FoundObjects;

        for (ClassType::const_iterator iter(m_deque.begin()); iter != m_deque.end(); ++iter)
        {
            if(/*Do some checks using iter*/)
            {
                FoundObjects.push_back(iter->get());
            }
        }

        return FoundObjects;
    }

private:

    typedef std::deque<std::unique_ptr<BaseClass>> ClassType;
    ClassType m_deque;
};

Так что в основном TempFuncName () возвращает список указателей BaseClass, удовлетворяющий некоторым условиям.Первоначально я думал о том, чтобы TempFuncName возвращал список unique_ptrs, но я чувствовал, что это разрушает всю цель использования unique_ptrs.Поэтому вместо этого я получаю необработанные указатели unique_ptr и push_back () этих необработанных указателей в список и возвращаю этот список.

Мне просто интересно, что я делаю (возвращаю необработанные указатели вместо unique_ptrs)на самом деле хорошая практика кодирования, или если это нормально, просто вернуть unique_ptrs (что я не думаю, что это хорошая идея с тех пор), или если я не должен даже использовать unique_ptrs в этой ситуации.

Я пробовал поискать в Google, но многоиз сообщений, которые я нашел, действительно не обсуждался этот конкретный вопрос, который у меня был.

Любая помощь и информация будет принята с благодарностью.

Ответы [ 3 ]

0 голосов
/ 31 января 2019

Давайте рассмотрим некоторые варианты того, что вы можете вернуть

Если вы вернете unique_ptr s, то по определению эти объекты больше не будут управляться менеджером.Похоже, что они все еще должны быть, поэтому unique_ptr не правильный тип.

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

Если вы точно знаете , что эти объекты существуют, например, потому что if отфильтровывает нули, это будет действительноприятно вернуться BaseClass & с.Проблема в том, что вы не можете иметь ссылку как value_type контейнера.В этом случае я бы использовал std::reference_wrapper<BaseClass> в качестве содержимого вашего контейнера, хотя BaseClass * не намного хуже, так как reference_wrapper в любом случае является в основном указателем.

Если нулевой указатель является допустимой опциейчтобы вернуться, вы не можете использовать ссылки, поэтому BaseClass * может быть вашим лучшим вариантом.

0 голосов
/ 31 января 2019

Использование необработанного владения указателем является плохой практикой.

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

Такие типы, как std::experimental::observer_ptr<T>, были введены для ясного выражения намерений.(но это в основном просто указатель).

Указатели-наблюдатели не владеют данными, поэтому время жизни данных должно быть длиннее, чем указатель-наблюдателя.

В вашем случае возможны следующие варианты:

class Manager
{
public:
    std::vector</*const*/ T*> filter_view_1(/**/) /*const*/;
    std::vector<std::experimental::observer_view</*const*/T>> filter_view_2(/**/) /*const*/;
    std::vector<std::reference_wrapper</*const*/T>> filter_view_3(/**/) /*const*/;


private:
    std::vector<std::unique_ptr<T>> data;
};

Таким образом, возвращаемые значения должны использоваться до того, как Manager::data будет «очищен».

Или, чтобы гарантировать срок службы:

class Manager
{
public:
    std::vector<std::shared_ptr</*const*/T>> filter_view_4(/**/) /*const*/;
    std::vector<std::weak_ptr</*const*/T>> filter_view_5(/**/) /*const*/;


private:
    std::vector<std::shared_ptr<T>> data;
};

filter_view_4 продлитьвремя жизни, тогда как filter_view_5 позволяет проверять время жизни объекта.

Существуют также различные подходы для недопущения внутреннего, такие как:

class Manager
{
public:
    // std::function might be replaced by template for the Functor
    void for_each_filtered(std::function<bool(const T&)> filter,
                           std::function<void(/*const*/ T&)> action) /*const*/
    {
        for (auto& d : data) {
            if (filter(*d)) {
                action(*d)
            }
        }
    }

private:
    std::vector<std::unique_ptr<T>> data;
};
0 голосов
/ 31 января 2019

Возвращает необработанный указатель вместо unique_ptr хорошей практики кодирования?

Нет.И да.Ответа нет, потому что это зависит от контекста.Однако это довольно просто:

Передача права собственности на ресурс с необработанным указателем является плохой практикой кодирования.

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

Эти соображения в общем верны и остаются верными в вашем конкретном примере.Вы должны решить, намереваетесь ли вы сохранить объекты в пределах Manager или намерены передать право собственности вызывающей стороне.Вы не удалили уникальные указатели в функции, поэтому кажется, что вы не хотите передавать права собственности.С третьей стороны, если вы намереваетесь разделить владельца, вам нужно использовать общие указатели повсюду.

...