我们有很多使用原始指针的现有代码,这些代码几乎在每次使用时都有空检查。
在尝试更清晰地编写更新的代码时,我们尝试使用工厂构造函数方法和unique_ptrs。
我的问题是,在下面的代码中,一旦有了工厂创建的对象sensorX,就可以在其余的代码中使用它,而无需对其进行进一步的空检查,因为它是const unique_ptr?>
DeviceFactory.h
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;
}
};
用法
const auto sensorX = DeviceFactory::create<Sensor>(123, "sensorX");
答案 0 :(得分:2)
好像您使用不太灵活的API编写了自己的std::make_unique
版本。我建议调整API,因为它会使升级变得更容易。
也就是说,您的问题与null检查有关。正如注释中多次指出的那样,您无需在获取指针后进行检查,因为应该抛出std :: bad_alloc。但是,我们假设您又抛出了一个这样的自定义异常检查,而主要问题是:您的API是什么,包括前置条件和后置条件。
在代码库中,除非另有说明,否则std :: unique_ptr不允许为nullptr。在这种情况下:无需进行空检查。您可以将其记录为nullptr,或者返回一个可选参数,以指示无效状态。
我的习惯是在使用前或创建后在指针上声明。但是,您可以使用Clang / Gcc清理程序来自动化该工作。 GSL还可以检查此nullptr的使用情况。
我的建议:在创建变量(或使用消毒剂)后进行断言,如果后置条件会发生变化,则应该在测试过程中发现错误。在与大学合作时,您应该同意除非记录了nullptr所代表的意思,否则不应该允许unique_ptr包含null。
答案 1 :(得分:1)
unique_ptr
仍然可以是nullptr
,这仅表示此对象处理基础资源,而不是存在已获取的资源。
因此,您仍然需要像以前一样检查对象是否存在。
旁注:是什么禁止某人致电您的工厂而不将结果存储在unique_ptr
中?只要允许,您就必须检查。
答案 2 :(得分:1)
即使它不是const unique_ptr常量,也可以执行此操作,前提是您永远不要将其重置为null。
在出厂功能上,
for i,x in enumerate(h):
exec(f'L{i}=x')
应该删除第二行中的检查,因为简单的普通 auto device = unique_ptr<T>{ new T{ id, status } };
if (!device) throw DeviceCreationException("device couldn't be created");
永远不会返回null(好吧,除非您对实现默认值做的事情确实很糟糕,否则,我认为)。
答案 3 :(得分:1)
首先测试:
if (!device) throw DeviceCreationException("device couldn't be created");
没什么意义,因为在达到该if子句时,device
不可能是nullptr
(至少对于给定的代码而言)>
从用户的角度来看,已知函数会由于签名而返回unique_ptr
,但是如果DeviceFactory::create<Sensor>
调用保证它不保存,则您需要阅读文档。 nullptr
。即使文档可以保证,对自己进行测试仍然是一个好主意,因为您不知道将来会一直如此。
所以问题是,如果您始终将其另存为const unique_ptr
,那么为什么根本不需要指针,而不要编写:
template<typename T>
static T create(int id, std::string status)
{
auto device = T{ id, status };
return device;
}
但是回到您的问题。如果const auto sensorX = ...
用不保存unique_ptr
的{{1}}进行了初始化,那么可以保证在整个生命周期内都不会nullptr
。
答案 4 :(得分:0)
一旦有了工厂创建的对象sensorX,我们是否可以在其余的代码中使用该对象而无需对其进行进一步的空检查?
如其他答案所示,答案为“否”。但是您 所能做的就是使用准则中的owner<>
模板(MS implementation)described:
owner<T*>
; owner<T*>
而不是T*
作为参数这将静态地保证 ,在拨打电话之前您已确保拥有owneshrip-因此您无需检查