C++ 从工厂方法返回的const unique_ptr不需要空检查?
我们有很多使用原始指针的现有代码,几乎在每次使用时都会出现空检查 在尝试更干净地编写新代码时,我们尝试使用工厂构造函数方法和唯一的\u ptr 我的问题是,在下面的代码中,一旦我们有了工厂创建的对象-sensorX-我们可以在代码的其余部分使用它而不需要进一步的空检查,因为它是一个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<
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”);
Aunique\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;
}