raii

Pelle Månsson pelle.mansson at gmail.com
Sun Feb 28 15:31:32 PST 2010


On 02/28/2010 09:16 PM, Ellery Newcomer wrote:
> Hello
>
> The impetus:
>
>> I agree, except I more and more think that scope classes were a
>> mistake. Structs with destructors are a much better solution, and
>> wrapping a class inside a struct would give it RAII semantics.
>
> The problem:
>
> In designing a library (or rather touching up someone else's library), I
> have a class (interface?) Foo, and it has a method close (actually
> several methods). Almost invariably (although conceivably not always),
> usage involves manipulating Foo, and then remembering to call close.
> That last part is obnoxious.
>
> One obtains a Foo from function foo.
>
> What I'd like is for the result of foo to have RAII semantics by
> default, with the possibility of nixing it if the user actually cares.
>
> I want to take the burden of remembering that stupid close off the user.
>
> For example:
>
> void bar(){
> auto a = foo();
> a.doStuff();
> }
>
> has an implicit call to close after doStuff.
>
> The impetus suggests I can do this by wrapping Foo inside a struct, but
> I'm not so sure how well this would work out. Also note that close can
> fail in a number of ways relating to file io.
>
> So I wrote up a simple prototype.
>
> Thoughts?
>
>
>
>
> import std.stdio;
> class Foo{
> int k;
> this(int i){
> writefln("bin %d",k);
> k = i;
> }
> void doStuff(){
> writefln("do stuff %d",k);
> }
> void close(){
> writefln("close %d",k);
> }
> }
> struct RAII(T){
> T b;
> bool extracted = false;
> alias b this;
> this (T i){
> assert(i !is null);
> writeln("in");
> b = i;
> }
> ~this(){
> writeln("~this");
> if(!extracted) b.close();
> }
> T extract(){
> assert(!extracted);
> T t = b;
> b = null;
> extracted = true;
> return t;
> }
> }
> RAII!(Foo) foo(int i){
> return RAII!(Foo)(new Foo(i));
> }
> void main(){
> auto a = foo(1);
> auto b = foo(2).extract();
> a.doStuff();
> b.doStuff();
> }
>
>

Maybe something along the lines of this

struct RAII(T : Object){
     T b;
     alias b this;

     void delegate(T) destroyer;

     this (T i, void delegate(T) called_at_exit){
         b = i;
         destroyer = called_at_exit;
     }
     ~this(){
         if (b) destroyer(b);
     }
     T extract(){
         T t = b;
         b = null;
         return t;
     }
}

class Foo {
     this() { }
     void close() {
         writeln("closed.");
     }
}

RAII!Foo foo() {
     return RAII!Foo(new Foo, (Foo f) {f.close;});
}

for a slightly more generalized RAII struct, which works on classes only.


More information about the Digitalmars-d-learn mailing list