Конструкторы в D, в общем, имеют что-то общее с С++, но с некоторыми исключениями:
class Constructors: Base
{
int a;
this(); //конструктор всегда зовут this. Что облегчает использование паттерна проектирования copy-paste :)this(int i) //как и в C++, конструкторов может быть несколько, они могут принимать параметры
{
a = i; //инициализация членов - просто в теле конструктораthis(); //в отличие от С++, конструкторы могут вызывать друг друга.
super(10); //вызов конструкторов базового класса - в любом месте конструктора. если нет явного вызова, вызовется в самом начале this(
}
int b = 18; //инициализация членов константами
~this() //с деструктором тоже все банально - он один, без параметров, всегда виртуальный
{
}
};
Статические конструкторы-деструкторы
Сюрприз! D позволяет каждому классу выполнять сколь угодно сложную инициализацию до начала функции main:
class A
{
int r = random(); //так нельзя!static this()
{
//это выполнится до начала main 1 раз. выделение ресурсов, задание начальных значений данных членов...
r = random(); //а вот так - можно!
}
static ~this()
{
//выполнится после конца main
}
}
Теоретически, пара статический конструктор/статический деструктор, возможно, подойдет для создания синглетонов...
RAII
RAII — фича, за отсутсвие которой обычно пеняют языкам с GC (а D — именно такой язык).
В С++ реализация RAII — лишь одно из следствий правил областей видимости и времени жизни переменной:
class Resource
{
Resource()
{
/*
открываем файлы, создаем сокеты и вообще творим всякие непотребства
*/
}
~Resource()
{
//убираем за собой
}
}
//где-то в коде:
{
Resource r; //взяли ресурс
....
} //ресурс освободился - даже в случае исключения
Поскольку в D все переменные пользовательских типов создаются выражением new и удаляются сборщиком мусора как-нибудь при случае, то такой фокус не пройдет. Поэтому в D можно явно сделать класс RAII классом:
autoclass Resource //весь фокус - тут
{
this()
{
/*
открываем файлы, создаем сокеты и вообще творим всякие непотребства
*/
}
~this()
{
//убираем за собой
}
}
//где-то в коде:
{
Resource r = new Resource; //так авто-классы использовать нельзяauto Resource r = new Resource; //только с явным указанием намерений
....
} //при выходе из scope - вызовутся деструкторы всех auto-переменных, ресурсы освободятся - даже в случае исключения
Здравствуйте, uw, Вы писали:
ЗХ>>Да я вот все думаю, с какой бы стороны подступиться к интеграции его с С++ными библиотеками... ИМХО, решение должно быть где-то рядом uw>SWIG
uw>Вроде кто-то реализовывал поддержку D. Самые новые исходники там, в svn репозитории. В каком это состоянии, я не в курсе, но возможно во вполне работоспособном. Вот страница с более старыми версиями(включая бинарники) и хоть каким-то описанием.
Вав! Про свиг знал, про то что он есть под D — даже предположить не мог. Получи заслуженную оценочку
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>>>А можно? Хочу Буду Влада пугать IT>>А ну ка попробуй чего-нибудь написать
ЗХ>ой, какая прелесть А можно это так и оставить?
Я тоже за, о великий и ужасный Зверёк.
ЗХ>ЗЫ: жаль, в Янусе все равно не видно
"Сказку о старике и рыбке" помнишь? Что там со старухой случилось?
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Сюрприз! D позволяет каждому классу выполнять сколь угодно сложную инициализацию до начала функции main: ЗХ>
ЗХ>class A
ЗХ>{
ЗХ> int r = random(); //так нельзя!
ЗХ> static this()
ЗХ> {
ЗХ> //это выполнится до начала main 1 раз. выделение ресурсов, задание начальных значений данных членов...
ЗХ> r = random(); //а вот так - можно!
ЗХ> }
ЗХ> static ~this()
ЗХ> {
ЗХ> //выполнится после конца main
ЗХ> }
ЗХ>}
ЗХ>
ЗХ>Теоретически, пара статический конструктор/статический деструктор, возможно, подойдет для создания синглетонов...
"возможно, подойдет для создания синглетонов..." собственно это они и есть.
Второе.
"инициализацию до начала функции main" это немного не так.
Вот исходник Harmonia WinMain, я выделил то место где инициализируются/"терминируются"
статические конструкторы/деструкторы
extern (C) void gc_init();
extern (C) void gc_term();
extern (C) void _minit();
extern (C) void _moduleCtor();
extern (C) void _moduleUnitTests();
extern (Windows)
int WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
int result = 0;
gc_init(); // initialize garbage collector
_minit(); // initialize module constructor tabletry
{
_moduleCtor(); // call module constructors
_moduleUnitTests(); // run unit tests (optional)
}
catch (Object o) // catch any uncaught exceptions
{
// failed [code skiped]....
result = -2;
}
if( result == 0 )
{
try
{
NativeApplication.initialize();
// main message pump loopwhile( true )
{
if(!NativeApplication.doEvents())
break;
}
result = 0;
}
catch (Object o) // catch any uncaught exceptions
{
result = -1; // failed
// [code skiped]
}
finally
{
NativeApplication.finalize();
}
}
gc_term(); // run finalizers; terminate garbage collectorreturn result;
}
Есть 2 точки деструкции объекта: когда его можно удалить (например, на объект есть единственная ссылка, и она выходит из зоны видимости), и когда объект действительно удаляется. Желательно иметь возможность написать свой код для обоих случаев. (auto — это да, а ещё?)
Можно ли вызывать виртуальные функции в конструкторах и деструкторах?
Здравствуйте, LCR, Вы писали:
LCR>c-smile:
LCR>Вот ещё два момента, из-за которых я плохо сплю: LCR> Есть 2 точки деструкции объекта: когда его можно удалить (например, на объект есть единственная ссылка, и она выходит из зоны видимости), и когда объект действительно удаляется. Желательно иметь возможность написать свой код для обоих случаев. (auto — это да, а ещё?)
"на объект есть единственная ссылка" это определить в принципе возможно
но вычислительно относительно дорого (нужно прогнать gc_mark).
Что можно сделать так это в деструкторе узнать "мы внутри GC или нет".
LCR> Можно ли вызывать виртуальные функции в конструкторах и деструкторах? LCR>Ы?
Здравствуйте, uw, Вы писали:
uw>Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>>Два последних оператора — не очень-то рулез по производительности. Зато по очевидности — это, имхо намного лучше, чем "многозначный" оператор из D uw>Этот "многозначный" оператор придуман в первую очередь для случаев, когда сравниваемые значения(или их часть) можно привести к целочисленному типу. Такая модель сравнения давным-давно используется скажем в libc(strcmp, qsort, итд), Java(интерфейс Comparable), .NET(IComparable).
uw>Что может быть проще и очевидней вот такого кода?
uw>
uw>class Task
uw>{
uw> private int priority;
uw> public int opCmp(Task t)
uw> {
uw> return priority - t.priority;
uw> }
uw>}
uw>
Здравствуйте, uw, Вы писали:
uw>Здравствуйте, McSeem2, Вы писали:
MS>>Повторю еще раз — в рамках арифметической записи задача нерешаема в любом языке. MS>>Другая часто возникающая потребность — получение частного и остатка. Во всех извесных мне архитектурах это делается одной командой DIV. Но вот мы пишем: MS>>
MS>>int lift = a/b;
MS>>int rem = a%b;
MS>>
MS>>И у нас нет ни малейшей гарантии того, что компилятор соптимизирует данную конструкцию в одну команду. А хотелось бы именно гарантии. Но для этого нужна специальная конструкция языка, причем весьма нетривиальная — с двумя взвращаемыми значениями.
uw>На самом деле работы в этом направлении(гарантированная оптимизация) ведутся, пока только исследовательские. И для этого не нужна будет специальная конструкция языка. Кстати два возвращаемых значения для функциональных языков(коими ни D,ни C++ естественно не являются) не проблема.
Здравствуйте, McSeem2, Вы писали:
MS>В высокоуровневых языках часто возникает ситуация "за лесом деревьев не видать". MS>Взять, хртя бы простейшее выражение (операция целочисленного масштабирования): MS>
MS>int v = a*b/c;
MS>
MS>a, b, c — все int. Так вот, на всех известных мне современных архитектурах, операция MUL выдает результат вдвое большей разрядности. А операция DIV тоже требует двойной разрядности. Таким образом, при использовании ассемблера, можно масштабировать целые значения практически во всем их диапазоне, не переходя на двойную разрядность целиком.
MS>Но копилятор обязан обрезать промежуточный результат a*b снова до одинарной разрядности и нет способа объяснить, что вот в данном случае обрезать не надо. Почему "обязан" — во-первых, компилятор не знает — может быть переполнение играет важную роль в данном алгоритме. Во-вторых, если мы усложним выражение: a*b*c/d — нам уже понадобится не двойная а тройная разрядность. Таким образом, в языках высокого уровня нет способа задействовать простую и эффективную последовательность инструкций mul/div. Таким образом, хотелось бы иметь что-то типа:
MS>
MS>Повторю еще раз — в рамках арифметической записи задача нерешаема в любом языке.
MS>Другая часто возникающая потребность — получение частного и остатка. Во всех извесных мне архитектурах это делается одной командой DIV. Но вот мы пишем: MS>
MS>int lift = a/b;
MS>int rem = a%b;
MS>
MS>И у нас нет ни малейшей гарантии того, что компилятор соптимизирует данную конструкцию в одну команду. А хотелось бы именно гарантии. Но для этого нужна специальная конструкция языка, причем весьма нетривиальная — с двумя взвращаемыми значениями.
Здравствуйте, Шахтер, Вы писали:
CS>>Здравствуйте, Шахтер, Вы писали:
uw>>>>
uw>>>>class Task
uw>>>>{
uw>>>> private int priority;
uw>>>> public int opCmp(Task t)
uw>>>> {
uw>>>> return priority - t.priority;
uw>>>> }
uw>>>>}
uw>>>>
Ш>>>Код некорректный.
CS>>Суров ты брат Шахтер и не многословен. CS>>Объясни что в этих двух соснах не так?
Ш>max_int > (-1) , max_int — (-1) == min_int < 0 .
Ах это! Ну дык там диапазон возможных
значений всего от -15 до 15 (Win32 thread priority levels)
А так, да, согласен — для краевых значений int это не работает.
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, Шахтер, Вы писали:
CS>>>Здравствуйте, Шахтер, Вы писали:
uw>>>>>
uw>>>>>class Task
uw>>>>>{
uw>>>>> private int priority;
uw>>>>> public int opCmp(Task t)
uw>>>>> {
uw>>>>> return priority - t.priority;
uw>>>>> }
uw>>>>>}
uw>>>>>
Ш>>>>Код некорректный.
CS>>>Суров ты брат Шахтер и не многословен. CS>>>Объясни что в этих двух соснах не так?
Ш>>max_int > (-1) , max_int — (-1) == min_int < 0 .
CS>Ах это! Ну дык там диапазон возможных CS>значений всего от -15 до 15 (Win32 thread priority levels)
CS>А так, да, согласен — для краевых значений int это не работает.
Если диапазон значений маленький, то да, но лучше на это не полагаться.