简体   繁体   English

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

[英]Is returning a raw pointer instead of unique_ptr good coding practice?

I've been studying unique_ptr and decided to write some simple code to make sure I've understood the concept and on how to use it. 我一直在研究unique_ptr并决定编写一些简单的代码来确保我已经理解了这个概念以及如何使用它。 What I have below is a Manager class, which has a deque that contains unique_ptrs. 我在下面是一个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;
};

So basically TempFuncName() will return a list of BaseClass pointers that satisfies some conditions. 因此,基本上TempFuncName()将返回满足某些条件的BaseClass指针列表。 I've originally thought of having the TempFuncName return a list of unique_ptrs, but I felt that defeats the whole purpose of using unique_ptrs. 我本来以为TempFuncName返回一个unique_ptrs列表,但是我觉得这违背了使用unique_ptrs的全部目的。 So instead, I get the raw pointers of the unique_ptr and push_back() those raw pointers into the list and return that list. 因此,我改为将unique_ptr的原始指针和push_back()的原始指针放入列表中并返回该列表。

I was just wondering if what I am doing (returning raw pointers instead of unique_ptrs) is actually good coding practice, or if it is okay to just return unique_ptrs (which I dont think is a good idea since) or if I shouldnt even use unique_ptrs in this situation. 我只是想知道我在做什么(返回原始指针而不是unique_ptrs)实际上是好的编码实践,还是只返回unique_ptrs(我认为这是个好主意)还是可以的,或者我是否甚至不应该使用unique_ptrs在这种情况下。

I've tried googling but a lot of the posts I found didnt really discuss this particular question I had. 我曾尝试使用Google搜索,但发现的很多帖子并没有真正讨论我遇到的这个特定问题。

Any help and information would be greatly appreciated. 任何帮助和信息将不胜感激。

Using raw owning pointer is bad practice. 使用原始拥有指针是不好的做法。

Using raw observer pointer is fine... but as existing code might use Raw owning pointers, raw pointer is ambiguous between observer pointer and owning pointer. 使用原始观察者指针是可以的...但是由于现有代码可能使用原始拥有者指针,因此观察者指针和拥有者指针之间的原始指针不明确。

Types such as std::experimental::observer_ptr<T> have been introduced to express intend clearly. 引入了诸如std::experimental::observer_ptr<T>类的类型来明确表达意图。 (but it is basically just a pointer). (但它基本上只是一个指针)。

Observer pointers don't own data, so lifetime of the data should be longer than Observer pointer. 观察者指针不拥有数据,因此数据的生存期应长于观察者指针。

In your case, possible choices include: 在您的情况下,可能的选择包括:

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;
};

So returned values should be used before that Manager::data is "cleaned". 因此,应在“清理” Manager::data之前使用返回值。

Or, to guaranty lifetime: 或者,为了保证使用寿命:

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 extend lifetime whereas filter_view_5 allows to check lifetime of object. filter_view_4延长了生存期,而filter_view_5允许检查对象的生存期。

There are also different approaches to not expose internal, such as: 还有一些不公开内部的方法,例如:

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;
};

Is returning a raw pointer instead of unique_ptr good coding practice? 返回原始指针而不是unique_ptr是好的编码习惯吗?

No. And yes. 不,是的。 There is no answer, because it depends on context. 没有答案,因为它取决于上下文。 It is fairly simple however: 但是,这很简单:

Transferring ownership of a resource with a raw pointer is a bad coding practice. 用原始指针转移资源所有权是一种不良的编码习惯。

Returning a non-owning pointer is a good practice (although in some cases a reference might be better). 返回非所有者指针是一个好习惯(尽管在某些情况下,引用可能会更好)。

These considerations are true in general, and remain true in your particular example. 这些注意事项通常是正确的,在您的特定示例中仍然适用。 You must consider whether you intend to keep the objects within Manager or are you intending to transfer the ownership to the caller. 您必须考虑是要将对象保留在Manager还是要将所有权转让给调用方。 You haven't removed the unique pointers in the function, so it appears that your intention is to not transfer the ownership. 您尚未删除函数中的唯一指针,因此看来您的意图是不转移所有权。 On the third hand, if you intend to share the ownership, then you need to use shared pointers throughout. 第三,如果您打算共享所有权,则需要在整个过程中使用共享指针。

Let's go through some options of what you can return 让我们看一下您可以退货的一些选项

If you return unique_ptr s, then by definition those objects are no longer being managed by the manager. 如果返回unique_ptr ,则根据定义,这些对象不再由管理器管理。 It sounds like they still should be, so unique_ptr is not the right type. 听起来好像还是应该的,所以unique_ptr不是正确的类型。

If you return shared_ptr s, or weak_ptr s, then you can be sure that later changes by the manager won't suddenly invalidate your values. 如果返回shared_ptrweak_ptr ,那么可以确保管理器以后进行的更改不会突然使您的值无效。 Either will mean that you change the queue to shared_ptr . 要么意味着您将队列更改为shared_ptr

If you know for sure that these objects exist, for example because the if filtered out nulls, it would be really nice to return BaseClass & s. 如果您确定知道这些对象的存在,例如因为if过滤出了null,则返回BaseClass & s非常好。 The problem is that you can't have a reference as the value_type of a container. 问题是您不能将引用作为容器的value_type In that case I would use std::reference_wrapper<BaseClass> as the contents of your container, although BaseClass * isn't much worse, as reference_wrapper is basically a pointer anyway. 在那种情况下,我将使用std::reference_wrapper<BaseClass>作为容器的内容,尽管BaseClass *并不差很多,因为reference_wrapper基本上是一个指针。

If a null pointer is a valid option to return, you can't use references, so BaseClass * may be your best option. 如果空指针是要返回的有效选项,则不能使用引用,因此BaseClass *可能是最佳选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM