Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stack-based object instantiation in D

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.

like image 899
anoncow Avatar asked Oct 23 '10 22:10

anoncow


3 Answers

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.

like image 87
Tim Čas Avatar answered Nov 05 '22 05:11

Tim Čas


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.

like image 37
dsimcha Avatar answered Nov 05 '22 06:11

dsimcha


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!

like image 1
anoncow Avatar answered Nov 05 '22 06:11

anoncow