一、背景
- 这种判断在项目代码中有很多:
handler_ = std::make_shared<UsbServerEventHandler>(eventRunner_, pms); if (handler_ == nullptr) {
USB_HILOGE(MODULE_USB_SERVICE, "Init failed due to create handler error"); return false; }
- 不同的人对此有不同的看法:
- 有人认为应该判空,防止以后使用
handler_
的时候对。 - 有人认为,make_shared失败后会抛出异常,而且
handler
值未定义,。
- 有人认为应该判空,防止以后使用
二、探索
1.构建失败场景
思路
- 目前我们可以肯定的是,
new(nothrow)
,可以申请内存,出错后会返回nullptr
。 - 因此可以使用
new
耗尽内存(包括虚拟内存),然后调用make_shared
,这样就可以构建失败的场景。
准备
- 环境信息
Desktop free total used free shared buff/cache available Mem: 3986712 1072260 119608 38116 2794844 2599996 Swap: 2097148 3148 2094000 ? Desktop df -lh Filesystem Size Used Avail Use% Mounted on tmpfs 390M 3.4M 386M 1% /run /dev/sda3 98G 13G 80G 14% / tmpfs 2.0G 0 2.0G 0% /dev/shm tmpfs 5.0M 4.0K 5.0M 1% /run/lock /dev/sda2 512M 5.3M 507M 2% /boot/efi tmpfs 390M 104K 390M 1% /run/user/1001 ? Desktop uname -a Linux ubuntu 5.13.0-20-generic #20-Ubuntu SMP Fri Oct 15 14:21:35 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
- 所以我们需要耗尽所有的内存。
- 耗尽后,使用
make_shared
申请内存,使其出错。
// make_shared.cpp #include <iostream> #include <cstdint> #include <memory> using namespace std; struct Memory {
uint8_t mem[UINT32_MAX];
};
int main()
{
for (uint32_t count = 0; count < UINT32_MAX; ++count) {
auto byte = new(nothrow) uint8_t[UINT32_MAX];
if (byte == nullptr) {
cout << "new failed in loop: " << count <<endl;
break;
}
}
auto shared = make_shared<Memory>();
cout << "finished!" << endl;
return 0;
}
2、不同场景下验证
使用异常
- 编译,不做优化
clang++ make_shared.cpp -O0 -o make_shared
- 运行
./make_shared
➜ projects ./make_shared
new failed in loop: 32766
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
[1] 20796 IOT instruction (core dumped) ./make_shared
禁用异常
- 编译,不做优化
clang++ make_shared.cpp -O0 -o make_shared -fno-exceptions
- 运行
./make_shared
new failed in loop: 32766
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
[1] 20836 IOT instruction (core dumped) ./make_shared
三、结论
- 通过上面的探索我们可以发现,