C++ 从工厂方法返回的const unique_ptr不需要空检查?

C++ 从工厂方法返回的const unique_ptr不需要空检查?,c++,c++11,unique-ptr,C++,C++11,Unique Ptr,我们有很多使用原始指针的现有代码,几乎在每次使用时都会出现空检查 在尝试更干净地编写新代码时,我们尝试使用工厂构造函数方法和唯一的\u ptr 我的问题是,在下面的代码中,一旦我们有了工厂创建的对象-sensorX-我们可以在代码的其余部分使用它而不需要进一步的空检查,因为它是一个const unique_ptr吗 设备工厂 class DeviceFactory { public: template<typename T> static unique_ptr<

我们有很多使用原始指针的现有代码,几乎在每次使用时都会出现空检查

在尝试更干净地编写新代码时,我们尝试使用工厂构造函数方法和唯一的\u ptr

我的问题是,在下面的代码中,一旦我们有了工厂创建的对象-sensorX-我们可以在代码的其余部分使用它而不需要进一步的空检查,因为它是一个const unique_ptr吗

设备工厂

class DeviceFactory
{
public:

    template<typename T>
    static unique_ptr<T> create(int id, std::string status)
    {
        auto device = unique_ptr<T>{ new T{ id, status } };

        if (!device) throw DeviceCreationException("device couldn't be created");

        return device;
    }
};
类设备工厂
{
公众:
模板
静态唯一\u ptr创建(int-id,std::string-status)
{
自动设备=unique_ptr{new T{id,status};
如果(!device)抛出DeviceCreationException(“无法创建设备”);
返回装置;
}
};
用法

const auto sensorX=DeviceFactory::create(123,“sensorX”);

A
unique\u ptr
仍然可以是
nullptr
,它只是意味着该对象处理底层资源,而不是存在已获取的资源

因此,您仍然需要像以前一样检查对象是否存在


旁注:什么东西禁止有人打电话给您的工厂,而不将结果存储在
唯一的\u ptr
?只要允许,您就必须进行检查。

即使它不是常量唯一\u ptr,只要您从未将其重置为null,您也可以进行检查

关于你的工厂职能

        auto device = unique_ptr<T>{ new T{ id, status } };
        if (!device) throw DeviceCreationException("device couldn't be created");
auto device=unique_ptr{new T{id,status};
如果(!device)抛出DeviceCreationException(“无法创建设备”);
签入第二行应该被删除,因为简单的普通
new
永远不会返回null(好吧,除非您对实现默认值做了非常糟糕的事情,我假定)。

首先测试:

if (!device) throw DeviceCreationException("device couldn't be created");
没有多大意义,因为在达到if子句时,
设备
不可能是
nullptr
(至少对于给定的代码是不可能的)

从用户的角度来看,已知函数由于签名而返回一个
unique\u ptr
,但是如果
DeviceFactory::create
调用保证它不包含
nullptr
,则需要阅读文档。即使文档能够保证这一点,您也可以自己测试它,因为您不知道将来会一直如此


因此,问题是如果您总是将其保存为
const unique\u ptr
,那么为什么您需要一个指针,而不是编写:

template<typename T>
static T create(int id, std::string status)
{
    auto device = T{ id, status };

    return device;
}
模板
静态T创建(int-id,std::string状态)
{
自动设备=T{id,status};
返回装置;
}
回到你的问题上来。如果
const auto sensorX=…
使用不保持
nullptr
unique_ptr
初始化,则保证在is生存期内不会
nullptr

一旦我们有了工厂创建的对象-sensorX-我们可以在代码的其余部分使用它而不需要进一步的空检查吗

正如其他答案所示,答案是“否”。但您可以使用指南中的
owner
模板():

  • 如果已建立指向工厂创建的对象的(原始)指针为非空,请将其包装在
    所有者中
  • 让所有权获取方法将
    owner
    而不是
    T*
    作为参数

这将静态地保证,在进行调用之前,您已经确保了ownership-因此您不需要检查看起来您使用一个不太灵活的API编写了自己版本的
std::make_unique
。我建议调整API,因为它将使升级更容易

也就是说,你的问题是关于空检查。正如注释中多次指出的,在获得指针后不需要进行检查,因为应该抛出std::bad_alloc。然而,让我们假设您有另一个抛出这种自定义异常的检查,而主要问题是:您的API是什么,包括前置和后置条件

在我们工作的代码库中,std::unique\u ptr不允许为null ptr,除非有文档记录。在这种情况下:不需要空检查。您可以将其记录为null ptr,或者返回一个可选值,这可能表示无效状态

我的习惯是在使用之前或创建之后对指针进行断言。但是,您可以通过使用Clang/Gcc的消毒剂来自动化这项工作。GSL还可以检查此nullptr的使用情况


我的建议是:在创建变量(或使用消毒剂)后断言,如果post条件发生变化,该变量应该在测试期间找到bug。与您所在的大学一起,您应该同意,除非记录了nullptr所代表的内容,否则unique_ptr不允许包含null。

使用
std::make_unique
然后编写自己的
your_cool_namespace::make_unique
。您的函数与
make_unique
相同(只有
如果(!设备)
是冗余的,它不能为空,因为
new
抛出)。没有必要重新发明轮子。(a) OP不能使用
make_unique
,所以他们自己编写。(b) 投稿人斥责OP没有使用
使_独一无二
。(c) OP指出他们不能使用
make_unique
。(d) 投稿人指示OP写他们自己的。(你无法编造!)如果你觉得你的代码有更多的空检查,这里是Herb Sutter关于指针、智能指针、引用和参数传递的一些指导@Eljay,感谢Herb Sutter链接-我们显然会在相关场景中考虑这些要点。“unique_ptr仍然可以是nullptr”-但在我上面的示例中,我已经做了“if(!device)”检查,并且创建的对象是const?您将这个unique_ptr作为const传递&无处不在?是的,我们希望尽可能地添加const,在哪里
template<typename T>
static T create(int id, std::string status)
{
    auto device = T{ id, status };

    return device;
}