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

Reply via email to