返回一个原始指针而不是unique_ptr是一种良好的编码实践吗

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

本文关键字:一种 编码 unique 原始 一个 指针 返回 ptr      更新时间:2023-10-16

我一直在研究unique_ptr,并决定写一些简单的代码来确保我已经理解了这个概念以及如何使用它。下面是一个Manager类,它有一个包含unique_ptrs的deque。

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_ptr的全部目的。因此,我将unique_ptr和push_back()的原始指针获取到列表中,并返回该列表。

我只是想知道我所做的(返回原始指针而不是unique_ptrs)是否真的是一种很好的编码实践,或者只返回unique_ptr是否可以(我认为这不是一个好主意),或者在这种情况下我甚至不应该使用unique_pTR。

我试过在谷歌上搜索,但我发现的很多帖子并没有真正讨论我的这个问题。

如有任何帮助和信息,我们将不胜感激。

让我们来看看您可以返回的一些选项

如果返回unique_ptrs,则根据定义这些对象不再由管理器管理。听起来它们仍然应该是,所以unique_ptr不是正确的类型。

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

如果您确信存在这些对象,例如因为if过滤掉了null,那么返回BaseClass &s将非常好。问题是,您不能将引用作为容器的value_type。在这种情况下,我会使用std::reference_wrapper<BaseClass>作为容器的内容,尽管BaseClass *并不差多少,因为reference_wrapper基本上是一个指针。

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

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

否。是的。没有答案,因为这取决于上下文。然而,它相当简单:

使用原始指针转移资源的所有权是一种糟糕的编码做法。

返回非拥有指针是一种很好的做法(尽管在某些情况下引用可能更好)。

这些考虑在一般情况下是正确的,在您的特定示例中也是正确的。您必须考虑是要将对象保留在Manager中,还是要将所有权转移给调用者。您还没有删除函数中的唯一指针,因此您的意图似乎是不转移所有权。第三方面,如果您打算共享所有权,则需要始终使用共享指针。

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

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

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

CCD_ 16延长了对象的寿命,而CCD_。

也有不同的方法不暴露内部,例如:

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;
};
相关文章: