On Wed, 02 Jun 2010 15:57:42 -0400, Andrei Alexandrescu <seewebsiteforem...@erdani.org> wrote:

On 06/02/2010 02:49 PM, Steven Schveighoffer wrote:
On Wed, 02 Jun 2010 15:34:32 -0400, Andrei Alexandrescu
<seewebsiteforem...@erdani.org> wrote:

On 06/02/2010 02:27 PM, Steven Schveighoffer wrote:
On Wed, 02 Jun 2010 15:16:53 -0400, Andrei Alexandrescu
<seewebsiteforem...@erdani.org> wrote:

On 06/02/2010 02:04 PM, Steven Schveighoffer wrote:
On Tue, 01 Jun 2010 21:59:20 -0400, Andrei Alexandrescu
<seewebsiteforem...@erdani.org> wrote:

On 06/01/2010 08:53 PM, bearophile wrote:
Andrei Alexandrescu Wrote:
Walter and I agreed to let it go, but somehow forgot to
announce it.

Are stack-allocated (scoped) classes too gone?

De facto no, de jure yes.

I don't really understand this. Are they going to be gone or not?

In any case, can we at least keep them for unsafe D? Stack
allocation is
not easy to do via placement new, the compiler is much better
suited for
it, and stack allocating classes can be a huge performance gain. Until
we get full escape analysis, scope classes are the only option.

There's no need for a language feature. I am implementing stack
allocation for classes in library code; I'm just undecided on where to
put it.

I think it belongs in druntime, since it's an allocation feature. How
easy is it to use?

The signature for non-class types is:

T* emplace(T, Args...)(void * address, Args args);

The function creates an object of type T at location address and
initializes it with args. Returns a pointer to the just-created value.
I needed this function for TightArray.

I haven't yet defined the signature for class types, but probably it
would look like this:

T emplace(T, Args...)(void * address, Args args);

To obtain stack allocation, you may therefore write something like:

auto obj = emplace(alloca(_traits(classInstanceSize, T)), stuff);

Although it uses the obscure classInstanceSize, I think it's near the
desired balance between terseness and making the programmer sweat for
a dangerous achievement.

This makes it better than scope classes for one reason -- it's an
expression instead of a declaration. That means I can use it to create a
temporary.

But I have some qualms here -- when is the object's destructor called? I
know it probably cannot be done any other way unless we had something
like macros, but it's not easy for humans to parse this mess. Sure, it
should be somewhat difficult for the developer to write, but what about
the reader? I suppose there just isn't an easy way to do this.

Also, wouldn't it have to be something like this:

auto obj = emplace!T(alloca(_traits(classInstanceSize, T)), stuff);

And finally, is there any possible way to write an emplace that uses an
allocator alias instead of the actual memory location? i.e.

T emplace2(T, alias alloc, Args...)(Args args)
{
return emplace!(T, Args)(alloc(_traits(classInstanceSize, T)), args);
}

Anything to avoid the double-specification of T would be nice. This of
course would be impossible to use with alloca without macros.

-Steve

Good points.

To ensure the destructor is called, I guess we need this:

@system struct StackAllocated(T)
{
     private ubyte buffer[__traits(classInstanceSize, T)] = void;
     @property T payload() { return cast(T) buffer.ptr; }
     alias payload this;
     @disable this(); // meh
     @disable this(this);
     this(Args...)(auto ref Args args)
     {
         emplace!T(buffer.ptr, buffer.length);
     }
     ~this()
     {
         clear(payload);
     }
}

Hm... is this valid usage then?

foo(StackAllocated!MyClass(a, b, c));

:)

-Steve

Reply via email to