Реализация объектов в стеке в D - PullRequest
6 голосов
/ 24 октября 2010

Я изучаю D, и меня смущает ошибка, которую я получаю.

Обратите внимание на следующее:

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()

Даёт вполне респектабельное:

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

Теперь рассмотрим, что происходит, когда я пытаюсь инициализировать PerformanceCounter в стеке вместо использования управляемой кучи:

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

Урожайность:

--- killed by signal 10

Я в тупике. Любые мысли о том, почему это ломается? (DMD 2.049 в Mac OS X 10.6.4). Заранее спасибо за помощь n00b.

Ответы [ 3 ]

5 голосов
/ 24 октября 2010

Вы, кажется, смешиваете классы C ++ с классами D.

D классы всегда передаются по ссылке (в отличие, скажем, от классов C ++), и PerformanceCounter t не выделяет класс в стеке, просто указывает на него.

Это означает, что t установлено в null, потому что, ну, null является инициализатором по умолчанию для указателей - отсюда и ошибка.

РЕДАКТИРОВАНИЕ: Вы можете думать о классе D Foo как о C ++ Foo*.

Если вы хотите, чтобы это было размещено в куче, вы можете попробовать вместо этого использовать структуры - они также могут иметь методы, как классы. Однако они не имеют наследства.

3 голосов
/ 24 октября 2010

Самый очевидный ответ - использовать struct. Если вы используете библиотеку, над которой у вас нет контроля или чего-то такого, и распределение кучи является проблемой производительности, вы можете использовать функциональность std.typecons.scoped для небезопасного размещения экземпляра класса в стеке. Экземпляр все еще передается по ссылке, и если его время жизни превышает время жизни текущего стекового фрейма, результатом будет неопределенное поведение. Ключевое слово scope в соответствии с ответом anoncow будет работать, но в D2 оно будет объявлено устаревшим.

1 голос
/ 24 октября 2010

Спасибо, Тим.

Благодаря вашему ответу я смог найти следующее на http://www.digitalmars.com/d/2.0/memory.html:


Распределение экземпляров класса в стеке

Экземпляры класса обычно размещаются в куче, собираемой мусором Однако если они: выделяются как локальные символы в функции распределяются с использованием новых использовать new без аргументов (аргументы конструктора разрешены) иметь класс хранения области затем они размещаются в стеке. Это более эффективно, чем выполнение цикла выделения / освобождения для экземпляра. Но будьте осторожны, чтобы любая ссылка на объект не сохранялась после возврата функции.

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

Если у класса есть деструктор, то этот деструктор гарантированно будет запущен, когда объект класса выйдет из области видимости, даже если область действия выходит из исключения.


Мой код теперь читается

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

Это (предположительно) размещается в стеке и работает нормально. :)

Еще раз спасибо!

...