Здравствуйте, vdimas, Вы писали:
EP>>Для таких случаев и сортировка вставками однопроходная, плюс для многих других. V>Сортировка вставками и так однопроходная.
Точно, подразумевал линейную сложность.
V>Но дороже пузырьковой при ситуации, близкой к лучшей.
Здравствуйте, gandjustas, Вы писали:
G>Это уже твои фантазии. Таких "замедляющих факторов" в любом языке полно, даже в c++. Более того, почти любые гарантии со стороны языка небесплатны. Супер оптимальный код будет супер небезопасным.
Считается наоборот. Код с дырами в безопасности не может быть оптимальным.
Здравствуйте, gandjustas, Вы писали:
G>Специально для тебя повторю — замедляющих факторов полно в любом языке. Даже в С++ (одни смартпоинтеры чего стоят).
Сами смарт-поинтеры ничего не стоят. Они не делают никакой лишней работы, которая не была бы сделана "ручками" в их отсутствие.
G>Так вот Java умеет девиртуализировать вызовы
Плюсы всегда девиртуализируют вызовы, когда известен точный тип объекта. Умели это еще до джавы.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
G>>Специально для тебя повторю — замедляющих факторов полно в любом языке. Даже в С++ (одни смартпоинтеры чего стоят).
V>Сами смарт-поинтеры ничего не стоят. Они не делают никакой лишней работы, которая не была бы сделана "ручками" в их отсутствие.
Ты о smart_ptr или о какой-то магии?
G>>Так вот Java умеет девиртуализировать вызовы V>Плюсы всегда девиртуализируют вызовы, когда известен точный тип объекта. Умели это еще до джавы.
"Всегда" это сколько по времени? Когда я занимался C++ в далеком 2006 не было девиртуализации в Visual Studio. А у джавы уже была насколько я знаю.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
G>>Это уже твои фантазии. Таких "замедляющих факторов" в любом языке полно, даже в c++. Более того, почти любые гарантии со стороны языка небесплатны. Супер оптимальный код будет супер небезопасным.
V>Считается наоборот. Код с дырами в безопасности не может быть оптимальным.
Не понял о чем ты. Представь типичную программу на C++ до C++11, теперь прикинь сколько и где надо добавить проверок в рантайме, чтобы исключить обращения к освобожденной памяти?
Здравствуйте, gandjustas, Вы писали:
G>>>Специально для тебя повторю — замедляющих факторов полно в любом языке. Даже в С++ (одни смартпоинтеры чего стоят). V>>Сами смарт-поинтеры ничего не стоят. Они не делают никакой лишней работы, которая не была бы сделана "ручками" в их отсутствие. G>Ты о smart_ptr или о какой-то магии?
Я довольно точно выразил свою мысль.
Смарт-поинтеры — это лишь элемент автоматизации имеющейся функциональности, а не привнесения новой.
Например, взять COM-объекты и какой-нить _com_ptr_t — абсолютно никаких дополнительных телодвижения этот _com_ptr_t не привнесет по сравнению с ситуацией, когда аналогичный код пишется без смарт-поинтеров (как в Паскале, например).
Такая же ситуация с другими смарт-поинтерами со счетчиками владения, типа intrusive_ptr.
Или без счетчиков, типа unique_ptr/auto_ptr.
G>>>Так вот Java умеет девиртуализировать вызовы V>>Плюсы всегда девиртуализируют вызовы, когда известен точный тип объекта. Умели это еще до джавы. G>"Всегда" это сколько по времени? Когда я занимался C++ в далеком 2006 не было девиртуализации в Visual Studio.
Ну вот так хорошо ты занимался.
struct A {
virtual void m() {
std::cout << "A";
}
};
struct B : A {
virtual void m() {
std::cout << "B";
A::m();
}
};
int main(int argc, char* argv[])
{
B b;
b.m();
return 0;
}
В дебажной-сборке вызывается без виртуализации по обычному call с прямой адресацией:
Здравствуйте, gandjustas, Вы писали:
V>>Считается наоборот. Код с дырами в безопасности не может быть оптимальным. G>Не понял о чем ты. Представь типичную программу на C++ до C++11, теперь прикинь сколько и где надо добавить проверок в рантайме, чтобы исключить обращения к освобожденной памяти?
А что изменилось после C++11 в этом плане? Это такой же дырявый язык по-умолчанию, как и C#.
Протягивать динамику в статику можно только через зависимые типы. В этом случае некая проверка происходит лишь однажды, при "динамическом преобразовании" неких исходных данных (взятых с IO, скажем) в "типизированную версию", а затем все гарантии распространяются автоматом, не требуя дальнейших проверок в рантайме. Именно отсюда растут ноги эффективности — из ГАРАНТИЙ безопасности.
Но С++ закрывает хотя бы часть амбразуры, если размерности массивов известны в compile-time. Т.е. можно так построить систему типов, чтобы протянуть всю безопасность далее по вызовам, сделав ненужным лишние проверки в каждом публичном методе. Например, хорошо это ложится на обработку данных порциями — мы выбираем размер порции в design-time, а затем в рантайм обрабатываем данные этими порциями, где все динамические проверки происходят аккурат в момент заполнения некоего начального "типизированного" буфера. Ну а далее будет уже как в языках с зависимыми типами — вся обработка будет уже без лишних проверок. К тому же это очень эффективно, т.к. все циклы задаются константными счетчиками, т.е. раскрутка цикла или операция сравнения на выход из цикла происходят в самых благоприятных для компилятора условиях.
Здравствуйте, vdimas, Вы писали:
EP>>Например? Дороже по какому параметру? V>По операции поиска места для вставки. Эта операция одинаково сложная для случая, когда надо поменять пару соседних или не соседних элементов.
Приведи пример. После swap'а пузырёк будет делать ещё проход.
Здравствуйте, vdimas, Вы писали:
V>Я довольно точно выразил свою мысль. V>Смарт-поинтеры — это лишь элемент автоматизации имеющейся функциональности, а не привнесения новой.
То есть нечто в C++ делает подсчет ссылок без smart_ptr? Что это?
V>Например, взять COM-объекты и какой-нить _com_ptr_t — абсолютно никаких дополнительных телодвижения этот _com_ptr_t не привнесет по сравнению с ситуацией, когда аналогичный код пишется без смарт-поинтеров (как в Паскале, например).
COM имеет подсчет ссылок независимо от C++.
V>Такая же ситуация с другими смарт-поинтерами со счетчиками владения, типа intrusive_ptr. V>Или без счетчиков, типа unique_ptr/auto_ptr.
Ты дурачка включил чтоли? Без умных указателей везде будут передаваться T*. А если мы все T* заменим на smart_ptr<T>, то подсчет ссылок сожрет производительность. Зато гарантированно не будет обращения к освобожденной памяти.
G>>>>Так вот Java умеет девиртуализировать вызовы V>>>Плюсы всегда девиртуализируют вызовы, когда известен точный тип объекта. Умели это еще до джавы. G>>"Всегда" это сколько по времени? Когда я занимался C++ в далеком 2006 не было девиртуализации в Visual Studio.
V>Ну вот так хорошо ты занимался. V>
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
V>>>Считается наоборот. Код с дырами в безопасности не может быть оптимальным. G>>Не понял о чем ты. Представь типичную программу на C++ до C++11, теперь прикинь сколько и где надо добавить проверок в рантайме, чтобы исключить обращения к освобожденной памяти?
V>А что изменилось после C++11 в этом плане?
После C++ умные указатели вошли в стандарт и стали основным способом работы. Это, кстати, позволяет намного сократить количество ошибок, но путем повышения тормозов. Если писать по старинке, через голые указатели, то очень много ошибок обращений к освобожденной памяти возникает, и довольно часто возникают утечки.
V>Протягивать динамику в статику можно только через зависимые типы. В этом случае некая проверка происходит лишь однажды, при "динамическом преобразовании" неких исходных данных (взятых с IO, скажем) в "типизированную версию", а затем все гарантии распространяются автоматом, не требуя дальнейших проверок в рантайме. Именно отсюда растут ноги эффективности — из ГАРАНТИЙ безопасности.
Это тебя в сторону унесло. Не нужны произвольные гарантии, их компилятор не обеспечит. Нужны базовые гарантии безопасности — отсутствие обращений к освобожденным объектам, отсутствие обращений к неинициализированной памяти, запрет реинтерпретации памяти. C++ с голыми указателями этого не дает. А совсем без голых указателей — привет тормоза и счетчиками ссылок.
Здравствуйте, gandjustas, Вы писали:
V>>Я довольно точно выразил свою мысль. V>>Смарт-поинтеры — это лишь элемент автоматизации имеющейся функциональности, а не привнесения новой. G>То есть нечто в C++ делает подсчет ссылок без smart_ptr? Что это?
Не в C++, а непосредственно в прикладной области возникают задачи, в которых точка удаления зависит от внешних параметров, неизвестных заранее.
V>>Такая же ситуация с другими смарт-поинтерами со счетчиками владения, типа intrusive_ptr. V>>Или без счетчиков, типа unique_ptr/auto_ptr. G>Ты дурачка включил чтоли?
Не хами.
G>Без умных указателей везде будут передаваться T*.
Неважно что будет передаваться. Подсчёт ссылок применим там где точка удаления зависит от внешних условий. Если же не использовать умные указатели, то эти условия всё равно придётся контролировать, чтобы сделать освобождение в правильном месте.
Пример: есть две параллельные (не пересекающиеся) асинхронные цепочки, у которых есть общие разделяемые ресурсы (отсюда и shared), которые должны быть освобождены после завершения обеих цепочек. Какая цепочка закончится первой — заранее неизвестно. Решить эту задачу можно например подсчётом ссылок, причём неважно — ручным или автоматическим. Но простого проставления освобождения ресурса в фиксированном месте здесь недостаточно.
G>А если мы все T* заменим на smart_ptr<T>, то подсчет ссылок сожрет производительность.
smart_ptr бывают разные, не обязательно с подсчётом ссылок. Подсчёт ссылок по факту нужен редко.
Здравствуйте, gandjustas, Вы писали:
V>>>>Считается наоборот. Код с дырами в безопасности не может быть оптимальным. G>>>Не понял о чем ты. Представь типичную программу на C++ до C++11, теперь прикинь сколько и где надо добавить проверок в рантайме, чтобы исключить обращения к освобожденной памяти? V>>А что изменилось после C++11 в этом плане? G>После C++ умные указатели вошли в стандарт
Там где требовалось их и так использовали. Стандартизировали лишь существующую практику, и то отчасти.
Самое существенное изменение C++11 относительно умных указателей это move семантика. Она конечно эмулировалась и в предыдущей версии стандарта, но с ограничениями.
G>и стали основным способом работы.
Основным способом работы с чем?
G>Это, кстати, позволяет намного сократить количество ошибок, но путем повышения тормозов. Если писать по старинке, через голые указатели, то очень много ошибок обращений к освобожденной памяти возникает, и довольно часто возникают утечки.
Что значит "по старинке"? По какой именно старинке?
И кстати голые не владеющие указатели прекрасно уживаются с умными.
G>Это тебя в сторону унесло. Не нужны произвольные гарантии, их компилятор не обеспечит. Нужны базовые гарантии безопасности — отсутствие обращений к освобожденным объектам, отсутствие обращений к неинициализированной памяти, запрет реинтерпретации памяти. C++ с голыми указателями этого не дает. А совсем без голых указателей — привет тормоза и счетчиками ссылок.
Это типичное заблуждение Java/C# программиста, мол там где у него new и владеющие указатели, то в C++ обязательно будет какой-нибудь умный/обычный указатель. Этот феномен даже Страуструп высмеивал — https://youtu.be/OB-bdWKwXsU?t=1984
По факту же в большинстве кода не нужны никакие владеющие указатели.
EP>Это типичное заблуждение Java/C# программиста, мол там где у него new и владеющие указатели, то в C++ обязательно будет какой-нибудь умный/обычный указатель. Этот феномен даже Страуструп высмеивал — https://youtu.be/OB-bdWKwXsU?t=1984 EP>По факту же в большинстве кода не нужны никакие владеющие указатели.
Так в итоге C#, Java, JS в топку? Все на С++?
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
EP>>Это типичное заблуждение Java/C# программиста, мол там где у него new и владеющие указатели, то в C++ обязательно будет какой-нибудь умный/обычный указатель. Этот феномен даже Страуструп высмеивал — https://youtu.be/OB-bdWKwXsU?t=1984 EP>>По факту же в большинстве кода не нужны никакие владеющие указатели. S> Так в итоге C#, Java, JS в топку? Все на С++?
Не, не в топку. Я сам частенько использую Python. И по секрету скажу, недавно даже на C# написал несколько сотен строк — правда это был пример использования C++ библиотеки, но тем не менее.
А вообще непонятно как ты сделал вывод про "в топку"
Здравствуйте, gandjustas, Вы писали:
G>То есть нечто в C++ делает подсчет ссылок без smart_ptr? Что это?
Это методы, навроде addRef/release.
V>>Например, взять COM-объекты и какой-нить _com_ptr_t — абсолютно никаких дополнительных телодвижения этот _com_ptr_t не привнесет по сравнению с ситуацией, когда аналогичный код пишется без смарт-поинтеров (как в Паскале, например). G>COM имеет подсчет ссылок независимо от C++.
COM-технология зиждется на таблице виртуальных ф-ий, генерённых компилятором С++.
Никакой "независимости" тут нет.
G>Ты дурачка включил чтоли?
началось...
G>Без умных указателей везде будут передаваться T*.
У меня и с умными указателями везде передаётся T*, и?
G>А если мы все T* заменим на smart_ptr<T>, то подсчет ссылок сожрет производительность.
Если у тебя везде передавался smart_ptr<T> в бытность твою плюсовиком, то прими мои поздравления с... да много с чем... ))
Для какой надобности?
G>Зато гарантированно не будет обращения к освобожденной памяти.
G>Девиртуализация вызовов это когда из кода:
G>
...
G>void f(A* a)
G>{
a->>m();
G>}
...
G>
G>Компилируется вызов b.m() без использования VMT.
Для девиртуализации необходимо изменение тела ф-ии под конкретный подаваемый тип. Это происходит при инлайнинге, например.
Никаких проблем:
int main(int argc, _TCHAR* argv[])
{
B b;
f(&b);
return 0;
}
Прекрасно обходимся без виртуального вызова.
Я же говорю, необходимо лишь, чтобы компилятор достоверно знал тип объекта.
Когда твоя джава получит указатель на объект "откуда-то еще", никакой девиртуализации при вызове не происходит, оно происходит аккурат в аналогичном приведенному сценарии.
Причем, для С++ это работает и в случае вложенных друг в друга объектах:
struct C {
B b;
};
int main(int argc, _TCHAR* argv[])
{
C c;
f(&c.b);
return 0;
}
Здравствуйте, gandjustas, Вы писали:
V>>А что изменилось после C++11 в этом плане? G>После C++ умные указатели вошли в стандарт и стали основным способом работы.
А по-факту — ничего не изменилось в реальных проектах, бо в стандарт вошли смарт-поинтеры из буста.
Смарт-поинтеры активно применяют примерно с середины 90-х.
G>Это, кстати, позволяет намного сократить количество ошибок, но путем повышения тормозов.
Я уже указывал на эту ошибку в этих рассуждениях. Ты фундаментально не прав. Смарт-поинтеры НЕ вносят тормозов, потому что не вносят никакой функциональности.
G>Если писать по старинке, через голые указатели, то очень много ошибок обращений к освобожденной памяти возникает, и довольно часто возникают утечки.
Дело не в старинке. Дело в том, что надо понимать, что ты делаешь.
А ты не понимаешь, очевидно.
Сосредоточься, плиз: смарт-поинтер нужен ровно там, где мы изменяем текущего владельца или расшариваем владение. Причем, при изменении текущего владельца через swap даже счетчики ссылок не дергаются.
V>>Протягивать динамику в статику можно только через зависимые типы. В этом случае некая проверка происходит лишь однажды, при "динамическом преобразовании" неких исходных данных (взятых с IO, скажем) в "типизированную версию", а затем все гарантии распространяются автоматом, не требуя дальнейших проверок в рантайме. Именно отсюда растут ноги эффективности — из ГАРАНТИЙ безопасности. G>Это тебя в сторону унесло.
Да нет, не в сторону. Речь-то пошла о гарантиях, даваемых языком / системой типов.
G>Не нужны произвольные гарантии, их компилятор не обеспечит.
Ну я-то готов обсуждать вполне конкретные гарантии, например, гарантии не выхода за пределы массива или гарантии необращения к удалённому объекту. И утверждаю, что в этом плане голый С++ стоит на уровне голого C#, бо оба языка НЕ обеспечивают таких гарантий.
G>Нужны базовые гарантии безопасности — отсутствие обращений к освобожденным объектам, отсутствие обращений к неинициализированной памяти,
G>запрет реинтерпретации памяти.
Для полного запрета реинтерпретации памяти необходимо отменить весь интероп, к примеру. А как вызывать ф-ии операционки?
G>C++ с голыми указателями этого не дает. А совсем без голых указателей — привет тормоза и счетчиками ссылок.
Похоже, ты опять не понимаешь, о чем говоришь. ))
C# не защищает нас ни о от обращения к удалённому объекту, ни от выхода за границы диапазонов. Сам язык не защищает. То, что он ловит такие моменты в рантайм — это просто рантайм проверки, которые не относятся к языку, а относятся к сгенерённому бинарнику (платформе исполнения в терминах дотнета). В С++ еще с тех времен, когда ты на нём писал, стояли галочки настройки компиляции как для проверки использования неинициализированных переменных, так и для проверки выхода за границы массивов. И поведение аналогичное — это вылет в рантайм при нарушении этих условий. Но сам-то язык никаких гарантий не даёт! ))
Некий участок, где возможен вылет за границы массива может быть не обнаружен никакими тестами в C#, потому что, например, может находиться в самом редком из комбинаций входных данных... Но у самого важного клиента оно обязательно вылетит, причем, в момент совершения важной сделки на 1 мегабакс. )) Программа всё-равно не сможет обработать транзакцию, как ты её не пинай, будет выдавать ошибку.
В общем, вылеты в рантайм — это ср-ва диагностики, ОК, сильно помогает искать ошибки. Эти ср-ва тебе так же доступны в С++. Но вне разработки —
это будет всё так же неработающая программа, которую "пропустил" тупой компилятор.
Я же рассуждал о возможности, скажем, исключить проверку на границы диапазонов в рантайм (все-равно это не защищает от ошибок), а сделать так, чтобы эту проверку производил компилятор С++ в compile-time. В этом случае, если обращение к такому массиву скомпилировалось, то выхода за границы заведомо не будет. В C# такой трюк недостижим.
Здравствуйте, vdimas, Вы писали:
V>Когда твоя джава получит указатель на объект "откуда-то еще", никакой девиртуализации при вызове не происходит, оно происходит аккурат в аналогичном приведенному сценарии.
Справедливости ради, в некоторых из таких случаев девиртуализацию может сделать JIT (который может быть в том числе и у программ C++; другое дело что на C++ обычно таких вызовов меньше).
Кстати, тут недавно был синтетический бенчмарк, в котором как раз был сделан сильный упор на JIT/девиртуализацию и GC, буквально задача на которой они раскрываются во всей красе — так даже и его получилось забороть