> 文档中心 > 【OpenHarmony】make_shared和make_unique失败时总会抛异常,和是否禁用异常无关

【OpenHarmony】make_shared和make_unique失败时总会抛异常,和是否禁用异常无关


一、背景

  • 在项目代码里面有很多这种判断:
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   availableMem:  3986712     1072260      11960838116     2794844     2599996Swap: 2097148 3148     2094000➜  Desktop df -lh Filesystem      Size  Used Avail Use% Mounted ontmpfs    390M  3.4M  386M   1% /run/dev/sda3 98G   13G   80G  14% /tmpfs    2.0G     0  2.0G   0% /dev/shmtmpfs    5.0M  4.0K  5.0M   1% /run/lock/dev/sda2512M  5.3M  507M   2% /boot/efitmpfs    390M  104K  390M   1% /run/user/1001➜  Desktop uname -aLinux 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 #include #include 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: 32766terminate 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: 32766terminate called after throwing an instance of 'std::bad_alloc'  what():  std::bad_alloc[1]    20836 IOT instruction (core dumped)  ./make_shared

三、结论

  • 通过上面的探索我们可以发现,不管在编译的时候是否禁用了异常,make_shared出错时,总会抛异常