views:

128

answers:

3

I'm learning D, and am confused by an error I'm getting.

Consider the following:

module helloworld;

import std.stdio;
import std.perf;

ptrdiff_t main( string[] args )
{
     auto t = new PerformanceCounter;    //From managed heap
     //PerformanceCounter t;             //On the stack

     t.start();
     writeln( "Hello, ", size_t.sizeof * 8, "-bit world!" );
     t.stop();

     writeln( "Elapsed time: ", t.microseconds, " \xb5s." );

     return 0;
} //main()

Yields a perfectly respectable:

Hello, 32-bit world!
Elapsed time: 218 µs.

Now consider what happens when I attempt to initialize PerformanceCounter on the stack instead of using the managed heap:

 //auto t = new PerformanceCounter;  //From managed heap
 PerformanceCounter t;               //On the stack

Yields:

--- killed by signal 10

I'm stumped. Any thoughts as to why this breaks? (DMD 2.049 on Mac OS X 10.6.4). Thanks in advance for helping a n00b.

+3  A: 

You seem to be mixing up C++ classes with D classes.

D classes are always passed by reference (unlike, say, C++ classes), and PerformanceCounter t does not allocate the class on the stack, merely a pointer to it.

This means that t is set to null because, well, null is the default initializer for pointers - hence the error.

EDIT: You can think of D Foo class as a C++'s Foo*.

If you want this to be allocated on the heap, you could try using structs instead - they can also have methods, just like classes. They do not, however, have inheritance.

Tim Čas
Thank you for the clue!! :) (That makes sense and also answers why the object dereference/member operator (->) isn't required.
anoncow
Well, the -> operator wouldn't be required anyways - for example, in C, the compiler (if smart enough) can actually warn you that you're using the wrong operator.In a similar manner, D's pointers (say, Foo*) do not need ->, but work with the dot: `Foo* foo = <whatever>; foo.bar = 5;`
Tim Čas
Sorry, I was referring to not needing it for the dynamically allocated object, not the stack-based one.
anoncow
If you know C# or Java, it might be more useful to think of D class instances as the same as C#'s and Javas.
Peter Alexander
Yep--great suggestion, thanks.
anoncow
+1  A: 

Thanks, Tim.

Thanks to your answer, I was able to find the following at http://www.digitalmars.com/d/2.0/memory.html:


Allocating Class Instances On The Stack

Class instances are normally allocated on the garbage collected heap. However, if they: are allocated as local symbols in a function are allocated using new use new with no arguments (constructor arguments are allowed) have the scope storage class then they are allocated on the stack. This is more efficient than doing an allocate/free cycle on the instance. But be careful that any reference to the object does not survive the return of the function.

class C { ... }

scope c = new C();  // c is allocated on the stack
scope c2 = new C(5);    // allocated on stack
scope c3 = new(5) C();  // allocated by a custom allocator

If the class has a destructor, then that destructor is guaranteed to be run when the class object goes out of scope, even if the scope is exited via an exception.


My code now reads

scope t = new PerformanceCounter();  //On the stack 

This (allegedly) allocates on the stack and runs fine. :)

Thanks again!

anoncow
As dsimcha points out in his post, however, scope is scheduled for deprecation, so it's not a good long term solution.
Jonathan M Davis
+3  A: 

The most obvious answer is to use a struct. If you're using a library that you don't have control over or something and the heap allocations are a performance problem, you can use the std.typecons.scoped functionality to unsafely allocate a class instance on the stack. The instance is still passed by reference and if its lifetime exceeds the lifetime of the current stack frame, undefined behavior will result. The scope keyword as per anoncow's answer will work, but is scheduled for deprecation in D2.

dsimcha
Oh no! I'd just fallen in love with scope, too! I'm using D2, so I'll go read up on why, this has been deprecated, sadly. Thank you for the struct suggestion--C++'s stack allocation mechanism suffers from the same gotcha as well.
anoncow
I believe that it has been deprecated essentially because it's unsafe. Having a class on the stack runs the risk of keeping a reference to it at after the function returns and having that reference no longer be valid. If it's on the heap, it won't be garbage collected until after all references to it are gone, so you won't have that problem.
Jonathan M Davis