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