返回一个原始指针而不是unique_ptr是一种良好的编码实践吗
Is returning a raw pointer instead of unique_ptr good coding practice?
我一直在研究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_ptr
s,则根据定义这些对象不再由管理器管理。听起来它们仍然应该是,所以unique_ptr
不是正确的类型。
如果返回shared_ptr
s或weak_ptr
s,则可以确保管理器稍后的更改不会突然使您的值无效。这两种情况都意味着您将队列更改为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;
};
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- 有一个打印语句的函数是一种糟糕的编程实践吗
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 有没有一种方法可以在编译时获得作用域类名
- 对于C++中使用智能指针的指针算术限制,有没有一种变通方法
- 一种在C++中读取TXT配置文件的简单方法
- 有没有一种方法可以测量c++程序的运行时内存使用情况
- 有没有一种方法可以使用placement new将堆叠对象分配给分配的内存
- 在调用接收数组的方法时,模板化数组大小是不是一种糟糕的做法
- 有没有一种方法可以通过"typedef"为重新定义的基本类型定义特征和强制转换运算符
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 有没有一种代码密度较低的方法来使用非默认构造函数初始化数组?
- 将错误返回给调用方而不是立即在 C++ 中抛出错误是否是一种好的做法
- 在 c++ 中,有一种方法可以创建一个包含地图作为值的树状地图?
- 有没有一种优雅而快速的方法来测试整数中的 1 位是否位于连续区域
- 需要帮助从12个字节生成新的24字节RGB查找阵列,或者是一种更好的编码方法
- 返回一个原始指针而不是unique_ptr是一种良好的编码实践吗
- 需要一种将我的Huffman树写入我的编码的方法
- 有没有一种方法可以在c++中检测Windows和Linux上的文件名编码
- 如何检测ICU中的一种编码是否支持unicode字符