Реализация объектов в стеке в D
Я изучаю 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 ответа
Вы, кажется, смешиваете классы C++ с классами D.
D классы всегда передаются по ссылке (в отличие, скажем, от классов C++), и PerformanceCounter t
не размещает класс в стеке, просто указывает на него.
Это означает, что t
установлен в null
потому что, ну, null
является инициализатором по умолчанию для указателей - следовательно, ошибка.
РЕДАКТИРОВАТЬ: Вы можете думать о D Foo
класс как C++ Foo*
,
Если вы хотите, чтобы это было размещено в куче, вы можете попробовать вместо этого использовать структуры - они также могут иметь методы, как классы. Однако они не имеют наследства.
Наиболее очевидный ответ заключается в использовании struct
, Если вы используете библиотеку, которую вы не можете контролировать или что-то в этом роде, и выделение кучи является проблемой производительности, вы можете использовать std.typecons.scoped
функциональность для небезопасного размещения экземпляра класса в стеке. Экземпляр по-прежнему передается по ссылке, и если его время жизни превышает время жизни текущего стекового кадра, результатом будет неопределенное поведение. scope
ключевое слово в соответствии с ответом anoncow будет работать, но в D2 запланировано устаревшее.
Спасибо, Тим.
Благодаря вашему ответу мне удалось найти следующее по адресу http://www.digitalmars.com/d/2.0/memory.html:
Распределение экземпляров класса на стеке
Экземпляры класса обычно размещаются в куче мусора. Однако, если они: выделены как локальные символы в функции, они распределяются с использованием new use 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
Это (предположительно) размещается в стеке и работает нормально.:)
Еще раз спасибо!