Здравствуйте, McSeem2, Вы писали:
MS>Здравствуйте, Шахтер, Вы писали:
Ш>>switch -- это и есть вычислимый goto. Только он мощнее. Поскольку метки могут быть непрерывным интервалом значений, в этом случае компилятор сгенерирует таблицу jam ов, или в случае, когда нет неперерывности -- двоичное дерево сравнений.
MS>Ты прав. Я тут сам запутался в своем словоблудстве. А хотел сказать нечто другое. Конструкция switch ничего не гарантирует. А хочется именно гарантированной оптимизации.
Гарантированной оптимизации язык дать не может. Он может дать только возможность оптимизации. Остальное зависит от качества компилятора.
Здравствуйте, Шахтер, Вы писали:
Ш>Гарантированной оптимизации язык дать не может. Он может дать только возможность оптимизации. Остальное зависит от качества компилятора.
Именно! В том-то и беда консткукции switch/case. Кмпилятор хоть что-то должен гарантировать. Это непростой вопрос, на самом деле. Комплятор типа C++ или Java или C# должен обеспечить сложность конструкции, не более зедекларированной. То есть, например, цикл for(i=0; i<N; i++) не может превышать O(N). Ну, при условии, что i и N — базовые типы, конечно же. В любом случае, такой цикл не может быть ни O(N^2), ни O(N log N). Другое дело, что в некоторых частных случаях, компилятор имеет право сгенерировать код, сложностью O(1), например, когда N — константа. Часто он так и поступает. Но гарантии нет. То же самое со switch. Компилятор в этом случае обязан гарантировать O(N), то есть, простой линейный поиск. Он имеет право сделать таблицу с бинарным поиском, имеет право сделать таблицу прямых переходов, если это возможно. Но нет ни малейшей гарантии того, что это будет сделано. И если мне нужна именно гарантия бинарного поиска по строкам, я не использую switch хоть в том же C#. Я использую именно бинарный поиск в явном виде и динамический полиморфизм. А если бы был вычисляемый goto, можно было бы поступить гораздо проще.
Предвижу возражения. Типа надо взять и посмотреть MSIL. Но с другой стороны, на все возможные компиляторы это не распространяется! Допустим, MS C# сгенерирует как надо. А Mono сгенерирует? А какой-нибудь левый компилятор имени Сидора Колобкова сгенерирует? Вот то-то и оно.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[6]: ЧАСТЬ 4: синтаксический сахар, синтаксический мусор..
Здравствуйте, McSeem2, Вы писали:
MS>Согласен с твоими выводами (нижеудалеными), но возражаю по поводу наличия в C++ типа "строка". Нет такого типа в языке.
Как же так, строки есть, а типа нету?
Re[7]: ЧАСТЬ 4: синтаксический сахар, синтаксический мусор..
MS>>Согласен с твоими выводами (нижеудалеными), но возражаю по поводу наличия в C++ типа "строка". Нет такого типа в языке. Т>Как же так, строки есть, а типа нету?
А что является строкой в C++?
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[8]: ЧАСТЬ 4: синтаксический сахар, синтаксический мусор..
Здравствуйте, FR, Вы писали:
FR>Можно ли в D сделать инициализацию переменных в шаблонах по умолчанию, например как перевести вот этот плюсовый код:
FR>
FR>template <typename T>
FR>struct Test
FR>{
FR> void fill(T* begin, int n, T t = T())
FR> {
FR> }
FR>};
FR>
FR>на D:
FR>
FR>struct Test(T)
FR>{
FR> void fill(T* begin, int n, T t = ???????)
FR> {
FR> }
FR>}
FR>
Начну с того что в D такой template (fill) просто не нужен, достатчно
написать по месту например так:
int* p = ...;
p[0..n] = somevalue;
Что в общем-то будет нагляднее.
Вариант наиболее близкий к тому что тебе надо можно найти в
имплементации Dictionary в Harmonia:
class Dictionary(KEY, VALUE)
{
private:
uint[KEY] map;
VALUE elements[];
public:
// get symbol of element, if it does not exist
// it will be created using ctor call
symbol opIndex(KEY key, VALUE function(KEY k) ctor)
{
symbol sym = map[key];
if( sym == 0 ) // it is not in dictionary yet
{
sym = cast(symbol)(elements.length + 1);
elements.length = sym;
elements[sym - 1] = ctor(key);
map[ key ] = sym;
}
return sym;
}
// get symbol of element, if it does not exist
// it will be silently created with default (init)
// value of the VALUE type
symbol opIndex(KEY key)
{
return map[key];
}
}
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, vdimas, Вы писали:
V>>Со всякими scope-контоллерами подобные алгоритмы не представляют трудностей, записываются "как под диктовку". В случае try-finally мы должны либо городить новый уровень вложенности на каждый №, либо усложнять блок finally, проверяя, что мы успели создать, а что нет. Получаем скорее деструктуризацию, чем структуризацию.
VD>Вот бы глянуть на подобный реальный код. А то реально деструкторы в 99% случаев память особождают...
Подобный код у нас был при загрузке удаленного файла во внутренний кеш по нашим внутренним интерфейсам.
1. Взятие потока из пула, в этом потоке далее:
2. Получение ссылки на удаленный объект — сессию закачки файла
3. Эту сессию необходимо явно "закрывать" в конце операций, ибо она держит конекшн к базе данных, откуда скачивается большой файл
4. Создание локального файла
5. Закачка очередного куска в цикле
6. Скидывание на диск, goto 3
Пункты 1-5 создают ресурсы, требующие контроля.
Автоматизируемые действия:
1 — возврат потока в пул
2 — уничтожение прокси
3 — явный вызов удаленного метода Release()
4 — удаление либо закрытие файла
5 — освобождение динамического буфера памяти
Сама закачка тоже такой из себя объект, который предоставляет информацию о текущем состоянии и принимает внешние "раздражители", и тоже, соответственно, контроллируется.
Эти внешние "раздражители" — суть объекты-команды (обрабатываются как события), которые передаются м/у потоками. Время их жизни тоже зависит от многих причин (успех/неуспех/не доехали до целевого треда ибо его больше нет и т.д.)
Итого имеем 7 ресурсов на ровном месте, требующих явного управления.
Было несколько вложенных и соседствующих try-catch, но исключительно работающих на локализацию стадии, на которой произошла ошибка, т.е. эти try-catch решали логические задачи, а не "механические", и их расположение и "охват" был соответствующий.
VD>Но ЖЦ конечно рулит. Тут ни плюся ни делифи и рядом не стояли.
И все-равно — спорный вопрос. Да, в подавляющем большинстве случаев он все-таки рулит. Особенно он рулит при контроле времени жизни объектов, используемых в нескольких потоках.
Для спец-задач, однако, рулят самописные менеджеры, и ничего пока с этим не поделать. (И не только блочного типа, о которых у тебя статья. Весьма быстры и полезны аллокаторы стекового типа, идеально подходящие для динамического выделения памяти для стековых оберток, априори работающих в одном потоке, там выделение и освобождение — суть двигание "верхней планки" текущего чанка, быстрее пока просто не придумано)
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, FR, Вы писали:
CS>Начну с того что в D такой template (fill) просто не нужен, достатчно CS>написать по месту например так:
fill у меня чисто для примера.
CS>Вариант наиболее близкий к тому что тебе надо можно найти в CS>имплементации Dictionary в Harmonia:
Угу но на C++ это гораздо красивей. Вообще есть очущение что шаблоны в D не доделаны.
Я правда нашел что у встроенных типов есть свойство .init которое можно использовать для инициализации по умолчанию, но я не понял что будет для классов у которых .init не реализован? Как я понял UB.
Здравствуйте, L.C.R., Вы писали: LCR>А вот обратная сторона медали: в Delphi невозможны умные указатели (и вообще, умные классы). Отсюда — насущная необходимость в finally, и обязательная уборка руками.
Реализация умных указателей(классов) для Delphi занимает в крайнем случае не
более 50 строк.
Re[10]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, vlad_gri, Вы писали:
LCR>>А вот обратная сторона медали: в Delphi невозможны умные указатели (и вообще, умные классы). Отсюда — насущная необходимость в finally, и обязательная уборка руками. _>Реализация умных указателей(классов) для Delphi занимает в крайнем случае не более 50 строк.
Не верю. Код в студию.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[11]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, vlad_gri, Вы писали:
LCR>>>А вот обратная сторона медали: в Delphi невозможны умные указатели (и вообще, умные классы). Отсюда — насущная необходимость в finally, и обязательная уборка руками. _>>Реализация умных указателей(классов) для Delphi занимает в крайнем случае не более 50 строк. WH>Не верю. Код в студию.
Наследоваться от TInterfacedObject
С уважением, Gleb.
... << RSDN@Home 1.1.4 beta 4 rev. 358>>
Re[12]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, GlebZ, Вы писали:
WH>>Не верю. Код в студию. GZ>Наследоваться от TInterfacedObject
А теперь сделай слабые ссылки. Или попробуй взять тип из чужой библиотеки который не отнаследован от TInterfacedObject...
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[13]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, WolfHound, Вы писали:
WH>А теперь сделай слабые ссылки. Или попробуй взять тип из чужой библиотеки который не отнаследован от TInterfacedObject...
Дяденька, я не сварщик, я каску на стройке нашел.
Мне тоже подобные идеи не нравятся, но они есть.
С уважением, Gleb.
... << RSDN@Home 1.1.4 beta 4 rev. 358>>
Re[11]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, vlad_gri, Вы писали:
_>>Реализация умных указателей(классов) для Delphi занимает в крайнем случае не более 50 строк. WH>Не верю. Код в студию.
Здравствуйте, vlad_gri, Вы писали:
_>>>Реализация умных указателей(классов) для Delphi занимает в крайнем случае не более 50 строк. WH>>Не верю. Код в студию. _>http://rsdn.ru/File/41945/AutoObjects.rar
Что случиться если этот код
procedure TForm1.Test_Auto_MemoryClick(Sender: TObject);
var
P : PChar;
begin
P := Auto_MemoryAlloc(32768).Ptr;
StrCopy(P, 'Hello there');
Caption := P;
end;
переписать так
procedure TForm1.Test_Auto_MemoryClick(Sender: TObject);
var
P : PChar;
i : Integer;
begin
for i := 0 to 1000000000 do
begin
P := Auto_MemoryAlloc(32768).Ptr;
StrCopy(P, 'Hello there');
Caption := P;
end;
end;
К томуже отсутствие типизации, накладные расходы...
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[13]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, WolfHound, Вы писали:
WH>Что случиться если этот код WH>переписать так WH>
WH>procedure TForm1.Test_Auto_MemoryClick(Sender: TObject);
WH>var
WH> P : PChar;
WH> i : Integer;
WH>begin
WH> for i := 0 to 1000000000 do
WH> begin
WH> P := Auto_MemoryAlloc(32768).Ptr;
WH> StrCopy(P, 'Hello there');
WH> Caption := P;
WH> end;
WH>end;
WH>
Закончится память, если ее недостаточно.
WH>К томуже отсутствие типизации, накладные расходы...
Отсутствие типизации присутствует
Какие накладные расходы
Re[14]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, vlad_gri, Вы писали:
_>Закончится память, если ее недостаточно.
Те всетки это ерунда, а не смартпоинтеры. Ибо в С++ в такой ситуации память не закончится(если ее конечно будет больше чем 32768).
А если там будет не память, а фаил или соеденение с БД или... то мы приедем гораздо раньше.
WH>>К томуже отсутствие типизации, накладные расходы... _>Отсутствие типизации присутствует
Вот именно что присутствует.
procedure TForm1.Test_Auto_ObjectClick(Sender: TObject);
var
SL:TFileStream;
begin
SL := Auto_MemoryAlloc(32768).Ptr;
Memo1.Lines.LoadFromStream(SL);
end;
К томуже если придется передать объект в другую функцию то придется передавать IAuto_Ptr _>Какие накладные расходы
На создание временного объекта в хипе, на вызов виртуальных методов, на сохранение IAuto_Ptr черт знает где.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[15]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, vlad_gri, Вы писали:
_>>Закончится память, если ее недостаточно.
Это я поторопился ответить.
На самом деле все происходит так-же как и в C++ т.е. в каждом цикле память освобождается.
WH>Те всетки это ерунда, а не смартпоинтеры. Ибо в С++ в такой ситуации память не закончится(если ее конечно будет больше чем 32768). WH>А если там будет не память, а фаил или соеденение с БД или... то мы приедем гораздо раньше.
WH>>>К томуже отсутствие типизации, накладные расходы... _>>Отсутствие типизации присутствует WH>Вот именно что присутствует.
WH>
В одной старой книжке по Turbo Pascal есть такие строки.
Стандартный тип-указатель Pointer дает указатель, не связанный ни с каким конкретным базовым типом.
Этот тип совместим с любым другим типом-указателем....
и еще
.... ответственность за правильность использования того или иного параметра возлагается на
программиста.
WH>К томуже если придется передать объект в другую функцию то придется передавать IAuto_Ptr
Как раз этого делать вовсе не обязательно.
procedure TForm1.Test_Auto_ObjectClick(Sender: TObject);
var
SL:TFileStream;
begin
SL := Auto_Object(TFileStream.Create('AutoObjects.pas',fmOpenRead)).Ptr;
// Передаем обьект SL в процедуру
Memo1.Lines.LoadFromStream(SL);
end;
_>>Какие накладные расходы WH>На создание временного объекта в хипе, на вызов виртуальных методов, на сохранение IAuto_Ptr черт знает где.
Каждый новый обьект занимает в хипе всего 16 байт.
Виртуальные методы вызываются только при создании и уничтожение IAuto_Ptr,
этим вполне можно пренебреч.
Что такое
черт знает где
лично я понятия не имею.
К стати реализация auto_ptr в C++ дает похожие накладные расходы.