返回原始指针而不是unique_ptr是好的编码习惯吗?

时间:2019-01-31 14:28:59

标签: c++ unique-ptr

我一直在研究unique_ptr并决定编写一些简单的代码来确保我已经理解了这个概念以及如何使用它。我在下面是一个Manager类,该类具有一个包含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 :(得分:1)

使用原始的拥有指针是不好的做法。

使用原始观察者指针是可以的...但是由于现有代码可能使用原始拥有者指针,因此观察者指针和拥有者指针之间的原始指针不明确。

已引入诸如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;
};

答案 1 :(得分:0)

  

是否返回原始指针而不是unique_ptr良好的编码习惯?

不。是的。没有答案,因为它取决于上下文。但是,这很简单:

使用原始指针转移资源所有权是一种不良的编码习惯。

返回非所有者指针是一个好习惯(尽管在某些情况下引用可能会更好)。

这些注意事项通常是正确的,在您的特定示例中仍然适用。您必须考虑是否打算将对象保留在Manager之内,还是要将所有权转移给调用者。您尚未删除函数中的唯一指针,因此看来您的意图是不转移所有权。第三,如果您打算共享所有权,则需要在整个过程中使用共享指针。

答案 2 :(得分:0)

让我们介绍一些您可以返回的内容

如果您返回unique_ptr,那么根据定义 这些对象将不再由管理者管理。听起来好像还是应该的,所以unique_ptr不是正确的类型。

如果返回shared_ptrweak_ptr,则可以确保经理以后的更改不会突然使您的值无效。这两种情况都意味着您将队列更改为shared_ptr

例如,如果您确定肯定存在这些对象,例如因为if过滤出了空值,那么返回BaseClass &真的很不错。问题是您不能将引用作为容器的value_type。在那种情况下,我将使用std::reference_wrapper<BaseClass>作为容器的内容,尽管BaseClass *并不差很多,因为reference_wrapper基本上还是一个指针。

如果空指针是要返回的有效选项,则不能使用引用,因此BaseClass *可能是最佳选择。