emplace, scope, enforce [Was: Re: Manual...]
Dmitry Olshansky
dmitry.olsh at gmail.com
Wed Jul 21 04:32:58 PDT 2010
On 21.07.2010 14:20, bearophile wrote:
> Dmitry Olshansky:
>
>> Well, I'm using this for structs, very straightforward:
>>
>> T* create(T, Args...)(Args args)
>> if ( !is(T == class) ){
>> return emplace!T(malloc(T.sizeof)[0..T.sizeof], args);
>> }
>>
> That's not good enough, you are allocating on the (C) heap. If you use that in the D benchmark I have shown you probably can get bad timing results.
>
>
Uh, yes I guess I should have read your post to the end :). Stack
allocation is risky business to say least. Some kind of memory pool
should be handy.
>> This is dtor not get called, and it's because emplace is a library
>> replacement for placement new( no pun).
>> Sure enough with manual memory management you need to call clear(t) at exit.
>>
> If the class is allocated on the stack it's much better if the destructor is called when the class gets out of scope. Otherwise it's like C programming.
> (I suggest to edit your post, to remove useless parts of the original post.)
>
>
To that end one should prefer vanilla structs with destructor, not final
classes and scope. That's, of course, losing the inheritance and such.
The problem is designing such classes and then documenting: "you should
always use it as 'scope' ", is awkward.
Moreover, the function which you pass the stack allocated class instance
are unaware of that clever trick.
Slight modification of your benchmark:
import std.conv: emplace;
import std.contracts;
import std.stdio;
final class Test { // 32 bytes each instance
int i1, i2, i3, i4, i5, i6;
this(int ii1, int ii2, int ii3, int ii4, int ii5, int ii6) {
this.i1 = ii1;
this.i2 = ii2;
this.i3 = ii3;
this.i4 = ii4;
this.i5 = ii5;
this.i6 = ii6;
}
void doSomething(int ii1, int ii2, int ii3, int ii4, int ii5, int
ii6) {
}
}
Test hidden;
void fun(Test t){
hidden = t;
}
void bench(){
enum int N = 10_000_000;
int i;
while (i < N) {
scope Test testObject = new Test(i, i, i, i, i, i);
fun(testObject);
testObject.doSomething(i, i, i, i, i, i);
testObject.doSomething(i, i, i, i, i, i);
testObject.doSomething(i, i, i, i, i, i);
testObject.doSomething(i, i, i, i, i, i);
i++;
}
}
void main() {
int a,b,c;//
bench();
//what's the hidden now?
writefln("%d %d", hidden.i1,hidden.i2);
writefln("%d %d", hidden.i1,hidden.i2);
}
The second writefln prints garbage. I guess it's because of pointer to
the long gone stackframe, which is ovewritten by the first writeln.
--
Dmitry Olshansky
More information about the Digitalmars-d
mailing list