真是後知後覺啊,最近才常是用這種方式。
先來用傳統的C語言分配資源寫法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| typedef struct B1 { ... } B1; typedef struct B2 { ... } B2; typedef struct D { B1 *p1; B2 *p2; } D; D* alloc_D() { D *obj = (D *)malloc(sizeof(D)); if (obj == NULL) return NULL; obj->p1 = (B1 *)malloc(sizeof(B1)); if (obj->p1 == NULL) { free(obj); return NULL; } obj->p2 = (B2 *)malloc(sizeof(B2)); if (obj->p2 == NULL) { free(obj->p1); free(obj); return NULL; } return obj; } void free_D(D *obj) { if (obj) { free(obj->p2); free(obj->p1); free(obj); } }
|
雖說用goto
可以簡化alloc的情況,不過要不要用goto
見仁見智。
如果是C++的話可以這樣寫
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| struct D { B1 *p1; B2 *p2; D() { try { p1 = new B1; p2 = new B2; } catch (...) { delete p2; delete p1; } } ~D() { delete p2; delete p1; } };
|
在Constructor中可以接收Exception,保證Object要嘛無法使用,要嘛是一個完整的狀態。
這邊看到刪除的部份程式碼重複了,因此用Smart pointer可以更進一步。
1 2 3 4 5 6
| struct D { unique_ptr<B1> p1; unique_ptr<B2> p2; D() : p1(new B1), p2(new B2) {} ~D() = default; };
|
Reference
– Is it ever not safe to throw an exception in a constructor?
– C++ : handle resources if constructors may throw exceptions