一、背景
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
- 所以我们需要耗尽所有的内存。
- 耗尽之后,在使用
make_shared 申请内存,使其出错。
#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
三、结论
- 通过上面的探索我们可以发现,不管在编译的时候是否禁用了异常,
make_shared 出错时,总会抛异常
|