Do smart pointers really eliminate the need for a two-phase design?

The two-phase design has the following form:

struct something { something () : p1(NULL) , p2(NULL) { } ~something () { if (p1) delete p1; if (p2) delete p2; } void initialize () { p1 = new int(2); p2 = new int(5); // May throw if allocation fails! } int* p1; int* p2; }; 

The point due to which the naive constructor (which does not monitor distribution failures) will be a memory leak: a partially destroyed destructor object is never called.

My question is: is the following code safe, and by proxy, smart pointers avoid a two-phase construct?

 struct something { something () : p1(new int(2)) , p2(new int(5)) { } std::unique_ptr<int> p1; std::unique_ptr<int> p2; }; 
+6
source share
3 answers

Yes, your new code is fine. Please note, however, that in more complex cases, more subtle are possible:

 #include <memory> struct foo { foo(std::shared_ptr<int> a, std::shared_ptr<int> b) { } }; struct bar { foo f; bar() : f(std::shared_ptr<int>(new int), std::shared_ptr<int>(new int)) { } }; int main() { bar b; } 

will not be safe, since the order of evaluation of the arguments of the constructor foo is not specified in the list of initializers bar . The corresponding compiler can choose the depth or width of the first order of evaluation (or something else if they are all evaluated correctly in the end). This means that if the first new int succeeds, and the second, before the shared_ptr objects were constructed, the first selection to be executed can still occur.

If you find that you want to do this, there are two possible solutions, in addition to simply returning to the two-phase construction: the first can be a refactor, the second is to build shared_ptr first as panel elements, before f . Which one is most appropriate is a call to court, which, it seems to me, needs to be done in each case.

+5
source

My question is: is the following code safe?

Yes, that will be fine.

 struct something { something () : p(new int(5)) { } std::unique_ptr<int> p; }; 

Please note that the naive code

 struct something { something () : p(new int(5)) { } int* p; }; 

will also be an exception, because there is only one highlight that can fail. I think you're talking more about

 struct something { something () : p(new int(5)), q(new int) { } int *p, *q; }; 

which will not be. In this case, smart pointers will work.

+5
source

You don't need a two-phase design at all if you just handle the exception. This is the way of the RIAA.

 struct something { something () : p1(NULL) , p2(NULL) { p1 = new int(2); try { p2 = new int(5); // May throw if allocation fails! } catch (std::bad_alloc&) { delete p1; //cleanup throw; //rethrow } } ~something () { delete p1; delete p2; } int* p1; int* p2; }; 
0
source

Source: https://habr.com/ru/post/901113/


All Articles