On Tue, Aug 27, 2013 at 04:01:57PM +0400, Dmitry Olshansky wrote:
> 27-Aug-2013 01:30, H. S. Teoh пишет:
> >On Sun, Aug 25, 2013 at 12:18:27AM +0200, Tobias Pankrath wrote:
> >>On Saturday, 24 August 2013 at 20:11:14 UTC, H. S. Teoh wrote:
> >>>How would you use RAII to solve this problem? If I have a class:
> >>>
> >>>   class C {
> >>>           Resource1 res1;
> >>>           Resource2 res2;
> >>>           Resource3 res3;
> >>>           this() {
> >>>                   ...
> >>>           }
> >>>   }
> >>>
> >>>How would you write the ctor with RAII such that if it successfully
> >>>inits res1 and res2, but throws before it inits res3, then only res1
> >>>and res2 will be cleaned up?
> >>
> >>Like someone else already proposed: Using a wrapper type W that
> >>releases the resources in it's destructor. W.init wouldn't release
> >>anything. So by definition (if I recall the rules correctly) every
> >>new instance of C would have res3 = Resource3.init prior to it's
> >>constructor called.
> >>
> >>Now make sure that a) res3's destructor gets called (check) b)
> >>res3's destructor may be called on Resource3.init. That would be a
> >>new rule similar to 'no internal aliasing' and c) that every
> >>constructor of C either sets res3 to a destructable value or does
> >>not touch it at all ('transactional programming').
> >[...]
> >
> >But don't you still need to manually cleanup in the case of ctor
> >failure? AFAIK, the dtor is not invoked on the partially-constructed
> >object if the ctor throws. So you'd still have to use scope(failure) to
> >manually release the resource.
> >
> >To prove my point, here is some sample code that (tries to) use RAII to
> >cleanup:
> >
> >     import std.stdio;
> >     
> >     struct Resource {
> >             int x = 0;
> >             this(int id) {
> >                     x = id;
> >                     writefln("Acquired resource %d", x);
> >             }
> >             ~this() {
> >                     if (x == 0)
> >                             writefln("Empty resource, no cleanup");
> >                     else
> >                             writefln("Cleanup resource %d", x);
> >             }
> >     }
> >     
> >     struct S {
> >             Resource res1;
> >             Resource res2;
> >             Resource res3;
> >     
> >             this(int) {
> >                     res1 = Resource(1);
> >                     res2 = Resource(2);
> >                     assert(res1.x == 1);
> >                     assert(res2.x == 2);
> >     
> >                     throw new Exception("ctor failed!");
> >                     res3 = Resource(3);     // not reached
> >                     assert(res3.x == 3);    // not reached
> >             }
> >     }
> >     
> >     void main() {
> >             try {
> >                     auto s = S(123);
> >             } catch(Exception e) {
> >                     writeln(e.msg);
> >             }
> >     }
> >
> >Here is the program output:
> >
> >     Acquired resource 1
> >     Empty resource, no cleanup
> >     Acquired resource 2
> >     Empty resource, no cleanup
> >     ctor failed!
> >
> >As you can see, the two resources acquired in the
> >partially-constructed object did NOT get cleaned up. So, RAII doesn't
> >work in this case.
> 
> Fixed?
> 
> >                     auto r1 = Resource(1);
> >                     auto r2 = Resource(2);
> >                     assert(res1.x == 1);
> >                     assert(res2.x == 2);
> >     
> >                     throw new Exception("ctor failed!");
> >                     auto r3 = Resource(3);  // not reached
> >                     assert(res3.x == 3);    // not reached
> 
>                       res1 = move(r1);
>                       res2 = move(r2);
>                       res3 = move(r3);
> 
> 
> Exception-safe code after all has to be exception safe.
> Unlike in C++ we have no explicit initialization of members (and
> strict order of this) hence no automatic partial cleanup.
[...]

What if move(r2) throws? Then res1 won't get cleaned up, because r1 has
already been nulled by the move.


T

-- 
Without outlines, life would be pointless.

Reply via email to