Re[27]: Конец нересурсов
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.11.11 00:00
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, samius, Вы писали:


S>>Отлично, но ведь такую точку входа не подружить с


V>Подружить запросто. Перегрузки ф-ий отличаются, будет выбрана более специализированная версия. Перегружается же как-то operator<< для всевозможных типов.


V>Например, у меня стоит такая ловушка для самого общего случая:

V>Которая генерит следующую ошибку при отсутствии специализации:
V>Для аналогичного показанному в пред.посте случаю есть специализация:
V>
V>    template<size_t N>
V>    inline TextBuilder& operator<<(const char(& data)[N]);
V>


а тот template<size_t N> inline void dosomething... был чисто оберткой над небезопасной функцией? Если да, то я зря запаниковал. Я просто подумал, что это и есть сама функция.

S>>Я прикопался не к типобезопасности, а именно к передаче размера массива темплейт параметром. Если такой метод используется часто с массивами различной длины, то будет взрыв размера бинариев, как я понимаю.


V>Да, в первых компиляторах С++ происходил именно взрыв размера бинарника. А потом оптимизатор link-time научился "склеивать" одинаковые куски кода. Что характерно, эта техника работает даже для нешаблонных и даже для виртуальных ф-ий, например:

Я тут как-то налабал комбинаторный парсер CSS на шаблонах. Ну то есть совершенно не постеснялся их использовать по случаю и без, любая комбинация принимала выводила типы параметров-парсеров и выдавала в качестве результата новый тип. Получил 5Мб бинарников. В этом случае оптимизатор link-time ничего сделать не мог даже теоретически.
Пришлось выделять абстракцию и учить комбинаторы работать с ней.

V>Признаюсь, я был сильно в 2002-м году удивлен, когда в релизном коде обнаружил, что getI и getF имеют один и тот же адрес, т.е. вместо двух ф-ий в бинарнике осталась только одна.



V>Для случая doSomething наиболее вероятным будет несколько сгенеренных точек входа (настоящих точек входа, без call и дополнительного фрейма стека, а просто jump потом на общее тело) с инициализацией какого-нить регистра или push в стек разных значений.

Вот, общее тело ведь принимает длину параметром метода, а не template-параметром? Если да, то вопрос снят.

V>Достоверно обещать не могу, это уж как оптимизатор выкрутится для конкретного кода, но использование нескольких легковесных точек входа, без создания лишних фреймов, наблюдаю постоянно. Особенно это неплохо смотрится если помнить, что в современных процах (со времен 2-го пня) безусловный jump занимает ровно 0 тактов.

Я использую точки входа, просто подумал на тот template что он есть общее тело.
Re[12]: Конец нересурсов
От: vdimas Россия  
Дата: 22.11.11 00:12
Оценка:
Здравствуйте, MxMsk, Вы писали:

MM>Мне требуется ликбез. Что в данном случае входит в понятие DOM? Я провел небольшой тест
Автор: MxMsk
Дата: 21.11.11
, по которому получается, что само чтение XAML-а, загрузка его контента, превращение стилей и шаблонов в описательные .Net объекты — вещь достаточно быстрая, плюс вовсю используется отоложенная загрузка по требованию. Однако, построение визуального дерева контролов уже затратная операция.


Дык, начинает работать "загрузка по требованию".
И не только всего, что связано с XAML, но и всей дотнетной инфраструктуры.

Кроме того, любой биндинг выполняет последовательно все probe на наличие той или иной технологии/соглашений для биндинга и выбирает первый подходящий вариант (см рефлектром). По моим замерам, это в среднем вдвое тормозило в сравнении с WinForms, бо там вариантов меньше рассматривается, и все эти варианты работают на рефлексии.

Ну и помимо прочего, не забываем про большее кол-во библиотек и типов, в т.ч. специализированных генериками, например, чуть ли не каждый экземпляр DependencyProperty — это новый тип, который требует инициализации. А вот иницализация типов — очень затратное дело. Ну и затем инициализация статиков практически в каждом типе WPF, а вызов каждого статического конструктора сопровождается глобальной блокировкой и ожиданием из других потоков (межпотоковые сигналы во всей красе). В общем, много чего набегает.

MM>Так вот, DOM — это загруженный описательный контент XAML или сформированное визуальное дерево контролов?


Елки, ну конечно дерево. Дерево — это и есть описательная часть композиции, которая по описанию строится нейтивным потоком, а XAML — это описание над описанием. Особенно шаблоны.
Re[9]: Конец нересурсов
От: vdimas Россия  
Дата: 22.11.11 00:17
Оценка:
Здравствуйте, AndrewVK, Вы писали:

V>>Теоретически работает?

AVK>Теоретически. Но ты ж за фундаментальное ограничение это выдавал.

Ну да. Просто инлайн, т.е. простая экономия на фреймах стека, это далеко еще не вся оптимизация. Но запрет на трансформацию представления данных, ввиду того, что

в дотнете, вообще все ф-ии экспортируемые с этой т.з. зрения

и там же вывод

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



AVK>А ты смотрел? Навскидку — основные изменения в 4 рантайме?


Я изменения смотрю по замерам, с некоторых пор.


AVK>Многие оптимизации можно сделать руками. В т.ч. с передвиганием в стек и обратно. Их отсутствие — никак не show stopper.


Дык, ручками и делается в обоих случаях.
Re[28]: Конец нересурсов
От: vdimas Россия  
Дата: 22.11.11 00:58
Оценка: 6 (1)
Здравствуйте, samius, Вы писали:

S>Я тут как-то налабал комбинаторный парсер CSS на шаблонах. Ну то есть совершенно не постеснялся их использовать по случаю и без, любая комбинация принимала выводила типы параметров-парсеров и выдавала в качестве результата новый тип. Получил 5Мб бинарников. В этом случае оптимизатор link-time ничего сделать не мог даже теоретически.

S>Пришлось выделять абстракцию и учить комбинаторы работать с ней.

Комбинаторные парсеры — это антинаучная лажа. Сорри, но сие так.

Более менее попытались вывести мат-аппарат для популярного здесь PEG-семейств грамматик (тоже близко к комбинаторным), но почитай критику и тонкие моменты таких парсеров. Я так и не созрел их юзать. А использовать произвольные комбинаторные парсеры — ну это разве что для "по-быстрому на коленке". Твои 5МB говорят о том, что минипарсеров было оч. много, т.е. на примитивный случай там никак не тянет. Надо было делать как положено: брать семейства GLR/LALR или LL(K). Навскидку, в CSS грамматике оч мало неодногзначностей (или нет совсем, так?), поэтому GLR или LL(1) парсеры будут отрабатывать за время, близкое к O(n), что комбинаторным и не снилось никогда. Ну и размер бинарника собственно парсера максимум в десятки К.

Правда, продолжать тему не буду, уже когда-то ломали копья и по поводу PEG и по поводу комбинаторных парсеров, легче найти те обсуждения, чем повторяться.


V>>Признаюсь, я был сильно в 2002-м году удивлен, когда в релизном коде обнаружил, что getI и getF имеют один и тот же адрес, т.е. вместо двух ф-ий в бинарнике осталась только одна.

S>

угу, размер-то типов одинаков, т.е. в терминах машинного кода всё одинаково.


S>Вот, общее тело ведь принимает длину параметром метода, а не template-параметром? Если да, то вопрос снят.


ммм... поясни мне, чем для снипета:
std::copy(src, src + size, dst);

разница, откуда был взят size, из параметра шаблона, или как константный параметр ф-ии? Для шаблонного, то бишь инлайного исполнения, эта разница стирается. Это код относительно безопасен в месте декларации (т.к. в одном экземпляре и скрее всего обложен юнит-тестом), но опасен во всевозможных местах вызова из всех сценариев и оперируемых типов данных, поэтому его неплохо иметь во внутреннем неймспейсе или в приватном методе, а в открытых иметь типобезопасные инлайные "точки входа".

S>Я использую точки входа, просто подумал на тот template что он есть общее тело.


Иногда он и есть единственное и неповторимое тело, если сами пишем, какие проблемы?
Все-равно внутри будет вызвана итерация по элементам через какой-нить STL/boost algorithm с каким-нить bind-замыканием, так что "точкой входа" было бы неплохо сделать код, выполняющий итерирование. И для контейнеров, совместимых с STL, тоже. Поэтому код точек входа мог быть другой, чем я приводил, если бы целевое тело писалось нами, а не было бы неким АПИ в стиле С, над которым мы делаем типобезопасные обертки.
Re[29]: Конец нересурсов
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.11.11 01:32
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, samius, Вы писали:


V>Комбинаторные парсеры — это антинаучная лажа. Сорри, но сие так.

А я не наукой занимаюсь.

V>Более менее попытались вывести мат-аппарат для популярного здесь PEG-семейств грамматик (тоже близко к комбинаторным), но почитай критику и тонкие моменты таких парсеров. Я так и не созрел их юзать.

Я тоже, потому и набросал комбинаторные.
V>А использовать произвольные комбинаторные парсеры — ну это разве что для "по-быстрому на коленке". Твои 5МB говорят о том, что минипарсеров было оч. много, т.е. на примитивный случай там никак не тянет.
Я написал, что каждый минипарсер представлял собой новый тип, параметризованный типами составляющих минипарсеров. Тут дело не вколичестве минипарсеров, а в глубине комбинаций. А вот как раз глубина комбинаций в CSS нехилая. Т.е. пока мы от тривиальных Char парсеров накомбинируем до stylesheet-парсера, набежит очень много типов парсеров. Когда ввел абстракцию, объем бинариев как рукой сняло, но все равно что-то около мегабайта было.
V>Надо было делать как положено: брать семейства GLR/LALR или LL(K). Навскидку, в CSS грамматике оч мало неодногзначностей (или нет совсем, так?), поэтому GLR или LL(1) парсеры будут отрабатывать за время, близкое к O(n), что комбинаторным и не снилось никогда. Ну и размер бинарника собственно парсера максимум в десятки К.
На как положено нет времени, скорость работы парсера не критична. Кстати, XML он парсил не сильно медленнее MSXML (навсикдку).

V>Правда, продолжать тему не буду, уже когда-то ломали копья и по поводу PEG и по поводу комбинаторных парсеров, легче найти те обсуждения, чем повторяться.

Не, не будем. У меня все работает, AST моё, парсеры мои, куда хочу, туда и расширяю, уговаривать переезжать на "как положенные варианты" меня не надо.

V>>>Признаюсь, я был сильно в 2002-м году удивлен, когда в релизном коде обнаружил, что getI и getF имеют один и тот же адрес, т.е. вместо двух ф-ий в бинарнике осталась только одна.

S>>

V>угу, размер-то типов одинаков, т.е. в терминах машинного кода всё одинаково.

И поле по тому же смещению... Совпадение. Рассчитывать на такую пруху, наверное не стоит.

S>>Вот, общее тело ведь принимает длину параметром метода, а не template-параметром? Если да, то вопрос снят.


V>ммм... поясни мне, чем для снипета:

V>
V>std::copy(src, src + size, dst);
V>

V>разница, откуда был взят size, из параметра шаблона, или как константный параметр ф-ии? Для шаблонного, то бишь инлайного исполнения, эта разница стирается.
Смущен. стоит ли мне напоминать о том, что константный параметр функции может быть определен во время выполнения, а параметр шаблона должен быть определен во время компиляции?

V>Это код относительно безопасен в месте декларации (т.к. в одном экземпляре и скрее всего обложен юнит-тестом), но опасен во всевозможных местах вызова из всех сценариев и оперируемых типов данных, поэтому его неплохо иметь во внутреннем неймспейсе или в приватном методе, а в открытых иметь типобезопасные инлайные "точки входа".

Согласен.

S>>Я использую точки входа, просто подумал на тот template что он есть общее тело.


V>Иногда он и есть единственное и неповторимое тело, если сами пишем, какие проблемы?

Проблемы в размере бинарников, если неповторимое нетривиальное тело параметризовано size-ом. Так, например, если я в основу CSS парсера клал тривиальные парсеры char-ов в виде CharParser<char C>(), то размер бинарника увеличивался на десятки килобайт по сравнению с использованием CharParser(char c). Что уж говорить о более высокоуровенвых комбинациях.

V>Все-равно внутри будет вызвана итерация по элементам через какой-нить STL/boost algorithm с каким-нить bind-замыканием, так что "точкой входа" было бы неплохо сделать код, выполняющий итерирование. И для контейнеров, совместимых с STL, тоже. Поэтому код точек входа мог быть другой, чем я приводил, если бы целевое тело писалось нами, а не было бы неким АПИ в стиле С, над которым мы делаем типобезопасные обертки.

Я теперь очкую размножить какой-нибудь код, потому обертки делаю, а нетривиальные тела делаю без template параметризации по мере возможности.
Re[21]: Конец нересурсов
От: Klatu  
Дата: 22.11.11 02:40
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Здравствуйте, Klatu, Вы писали:


V>>>>>Она встречается на несколько порядков чаще в дотнете, да и в нейтиве тоже, чем проходы по памяти.

K>>>>ну это просто вранье или полная некомпетентность
ГВ>>>Слушай, найди какой-нибудь другой аргумент, а?
K>>Ну а что поделаешь. Прога, которая сломалась потому что (очевидно, глобальное/статическое) поле кто-то обнулил [...]

ГВ>На этом варианты закончились? Только глобальное/статическое?


ну попробуй придумай другой вариант
Re[19]: Конец нересурсов
От: Klatu  
Дата: 22.11.11 02:42
Оценка:
Здравствуйте, Banned by IT, Вы писали:

BBI>Здравствуйте, Klatu, Вы писали:


K>>Я пока что не встречал более пафосных говнокодеров, чем на С++. Вот это — точно медицинский факт. Каждое нубло, которое накропало пару примитивных программок на С++ — уже считает себя гуру

BBI>Брысь зелёный, еды не будет. Тоньше надо троллить, тоньше!

да у вас троллефобия, голубчик. не запускайте, это опасно
Re[30]: Конец нересурсов
От: vdimas Россия  
Дата: 22.11.11 02:53
Оценка:
Здравствуйте, samius, Вы писали:

V>>угу, размер-то типов одинаков, т.е. в терминах машинного кода всё одинаково.

S>И поле по тому же смещению... Совпадение. Рассчитывать на такую пруху, наверное не стоит.

Разумеется не стоит. Задача компилятора колдовать как угодно, но обеспечить исходную семантику. Где повезет, там повезет. Но чем больше проект, тем больше доля относительного везения.

S>Смущен. стоит ли мне напоминать о том, что константный параметр функции может быть определен во время выполнения, а параметр шаблона должен быть определен во время компиляции?


Дык, и исходная размерность может быть известна не только в compile-time. Да и уточнил уже ниже абзацем.

V>>Иногда он и есть единственное и неповторимое тело, если сами пишем, какие проблемы?

S>Проблемы в размере бинарников, если неповторимое нетривиальное тело параметризовано size-ом. Так, например, если я в основу CSS парсера клал тривиальные парсеры char-ов в виде CharParser<char C>(), то размер бинарника увеличивался на десятки килобайт по сравнению с использованием CharParser(char c). Что уж говорить о более высокоуровенвых комбинациях.

Вообще, для случая inline-исполнения оба варианта эквивалентны, и там и там протягивается константа времени компиляции. Ты, случайно, не определял тела методов за пределами класса без inline?
Есть еще версия, что уровень максимальной вложенности, рассматриваемый компилятором, ограничен (оно так и есть, иначе бы программа компиллировалась бесконечно, бо слишком много комбинаций получалось бы на самом верхнем уровне). Но мы не знаем ни уровня такой вложенности компилятора (для GCC недавно было 8 вроде), ни получаемого у тебя уровня вложенности на верхнем уровне.

Возможно, стоило вывести несколько "промежуточных" достаточно высокоуровневых фиксированных типов парсеров (параметризируемых обычными аргументами, а не шаблонными), именно на них уменьшив общее комбинаторное число, а не на самых низкоуровневых. Смотреть надо и пробовать.

V>>Все-равно внутри будет вызвана итерация по элементам через какой-нить STL/boost algorithm с каким-нить bind-замыканием, так что "точкой входа" было бы неплохо сделать код, выполняющий итерирование. И для контейнеров, совместимых с STL, тоже. Поэтому код точек входа мог быть другой, чем я приводил, если бы целевое тело писалось нами, а не было бы неким АПИ в стиле С, над которым мы делаем типобезопасные обертки.

S>Я теперь очкую размножить какой-нибудь код, потому обертки делаю, а нетривиальные тела делаю без template параметризации по мере возможности.

А я просто пользуюсь тем, что декомпозиция в С++ практически бесплатна, в отличие от. Оч удобно декомпозировать на совсем маленькие типы с некоторым заведомо безопасным интерфейсом, с проверкой всех контрактов и прочим, затем построить глобальные операции вокруг таких типов (тоже оч удобно в отличие от ). В таком подходе высокоуровневые объекты "по месту" собираются уже из отлаженных запчастей такой инфраструктуры, которая получается высокоуровневой сама по себе, потому что в прикладном коде мы уже оперируем прикладными сущностями из инфраструктуры.

В этом и есть С+ философия: как можно больше прикладной логики отразить во взаимоотношениях типов и операций м/у ними. Т.к. операции порой довольно-таки обоюдные, чтобы не ломать голову, методом какого объекта организовать операцию, её таки удобнее делать глобальной на основе самого базового публичного интерфейса прикладных типов (которые суть отвечают за безопасность и соблюдение инвариантов приватного состояния).

Более высокоуровневые типы и операции м/у ними строятся точно так же на основе низкоуровневых и далее по иерархии, и вот тут, если принять некие единообразные правила игры, то типизируемость на шаблонах начинает показывать весь свой профит. Потому как они действительно многократно повторно используемы могут быть лишь в глобальных ф-ях, обслуживая от простых операций, до целых сложных "паттернов" (местного разлива в т.ч.) в отличие от, где низкое повторное использование кода, да еще с ограничением размещения лишь в методах, и где библиотечная/обобщенная реализация паттернов затруднительна, из-за ограничений технологии генериков.
Re[17]: Конец нересурсов
От: Sinclair Россия https://github.com/evilguest/
Дата: 22.11.11 03:16
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Не вижу здесь чего-то удивительного. Разработчик с 3-х летним опытом всяко должен отличаться от разработчика с опытом в год. Как раз, по моим наблюдениям, в хорошей среде программист С++ за примерно 3 года овладевает всеми обсуждаемыми приемами на уровне мозжечка. А если учесть, что средний стаж программистов в наше время поболе 5-ти лет, я вообще не вижу проблем.

Осталось показать код. А то получается, что теоретически программисты владеют всеми приёмами на уровне мозжечка, а на практике пишут совершенно без них.

V>У дотнетных приложений есть своя ниша, где эффективность не важна. Утилиты какие-нить, всякие SOAP-сервисы, генерация HTML и прочее из той же оперы... ИМХО, споры возникают по причине неправильного позиционирования дотнета. Как только обсуждающие сходятся на том, что каждому инструменту своя ниша, так споры утихают сами собой.

Ну, это правда. Да.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[31]: Конец нересурсов
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.11.11 03:35
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, samius, Вы писали:


S>>Проблемы в размере бинарников, если неповторимое нетривиальное тело параметризовано size-ом. Так, например, если я в основу CSS парсера клал тривиальные парсеры char-ов в виде CharParser<char C>(), то размер бинарника увеличивался на десятки килобайт по сравнению с использованием CharParser(char c). Что уж говорить о более высокоуровенвых комбинациях.


V>Вообще, для случая inline-исполнения оба варианта эквивалентны, и там и там протягивается константа времени компиляции. Ты, случайно, не определял тела методов за пределами класса без inline?

Случайно тела методов были в теле класса. Те методы однострочные, жалко было места для дублирования сигнатуры. Но раз я обнаружил разницу в размере бинарников, то очевидно что варианты не эквивалентны. Тем более, что класс во втором случае имеет поле, в котором хранит переданный в конструкторе char.

V>Есть еще версия, что уровень максимальной вложенности, рассматриваемый компилятором, ограничен (оно так и есть, иначе бы программа компиллировалась бесконечно, бо слишком много комбинаций получалось бы на самом верхнем уровне). Но мы не знаем ни уровня такой вложенности компилятора (для GCC недавно было 8 вроде), ни получаемого у тебя уровня вложенности на верхнем уровне.

комбинаций немало (http://www.w3.org/TR/CSS2/grammar.html#scanner, http://www.w3.org/TR/CSS2/grammar.html#grammar)

V>Возможно, стоило вывести несколько "промежуточных" достаточно высокоуровневых фиксированных типов парсеров (параметризируемых обычными аргументами, а не шаблонными), именно на них уменьшив общее комбинаторное число, а не на самых низкоуровневых. Смотреть надо и пробовать.

Я так и сделал. Параметризовал тип парсера лишь типом его результата, и убрал типы парсеров-участников комбинации.

S>>Я теперь очкую размножить какой-нибудь код, потому обертки делаю, а нетривиальные тела делаю без template параметризации по мере возможности.


V>А я просто пользуюсь тем, что декомпозиция в С++ практически бесплатна, в отличие от. Оч удобно декомпозировать на совсем маленькие типы с некоторым заведомо безопасным интерфейсом, с проверкой всех контрактов и прочим, затем построить глобальные операции вокруг таких типов (тоже оч удобно в отличие от ). В таком подходе высокоуровневые объекты "по месту" собираются уже из отлаженных запчастей такой инфраструктуры, которая получается высокоуровневой сама по себе, потому что в прикладном коде мы уже оперируем прикладными сущностями из инфраструктуры.

Если я все верно понял, то это справедливо не только для C++

V>В этом и есть С+ философия: как можно больше прикладной логики отразить во взаимоотношениях типов и операций м/у ними. Т.к. операции порой довольно-таки обоюдные, чтобы не ломать голову, методом какого объекта организовать операцию, её таки удобнее делать глобальной на основе самого базового публичного интерфейса прикладных типов (которые суть отвечают за безопасность и соблюдение инвариантов приватного состояния).


V>Более высокоуровневые типы и операции м/у ними строятся точно так же на основе низкоуровневых и далее по иерархии, и вот тут, если принять некие единообразные правила игры, то типизируемость на шаблонах начинает показывать весь свой профит. Потому как они действительно многократно повторно используемы могут быть лишь в глобальных ф-ях, обслуживая от простых операций, до целых сложных "паттернов" (местного разлива в т.ч.) в отличие от, где низкое повторное использование кода, да еще с ограничением размещения лишь в методах, и где библиотечная/обобщенная реализация паттернов затруднительна, из-за ограничений технологии генериков.

генерики они другие. На темплейтах можно делать то, что нельзя на генериках и наоборот. Например, был жестоко обломан тем что темлейт функции-мемберы не могут быть виртуальными
Вот еще пример, рекурсивный полиморфизм невозможно юзать во времени выполнения в C++, но вполне работает в C#. Если что — я об Purely Functional Data Structures (Queues based on implicit recursive slowdown).
Re[16]: Конец нересурсов
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 22.11.11 03:58
Оценка: 34 (2) +2
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Геннадий Васильев, Вы писали:


ГВ>>Пользовал и пользую; писал и пишу; применяю, где имеет смысл и не применяю, где не имеет смысла.

S>Верю. Всем остальным — тоже верю. Я же говорю: на форумах — все гуру. А в реальности закрытый С++ код, который я видел, в среднем намного хуже того Open-source, который вроде написан непонятно кем.

ГВ>>Никто никого никуда не зовёт. Нравится дотнет — пиши для дотнет, кто мешает-то? Только не надо при этом плеваться в сторону С++.

ГВ>>Ни ногой, так ни ногой, только зачем шуметь, если кто-то констатирует объективные недостатки того же дотнета, не зависящие от программистов?
S>Да вроде никто не плюётся. Средний дотнетчик редко затевает топики типа "оппа, плюсам-то капец!".

А можно узнать, где в топикстарте есть что-нибудь про "шарпу капец"? Топик называется, напоминаю: "Конец нересурсов".

S>Всё как раз наоборот: начинаются какие-то наезды на управляемый код (без малейшего желания хотя бы выяснить, что вообще такое управляемый код.


По ссылкам из топикстарта всё-всё сказано. Ни о каких "шарпу — конец" там даже близко речи не идёт. Собственно, грызня началась из-за любимой шарпистами темы — изобилия ошибок в плюсовом коде.

S>Признайся честно — ведь не читал определение из ECMA-335, да?), вопросы типа "а как вы будете писать драйвер" и прочее, навязшее уже в зубах.


У тебя, я так думаю, это определение тоже не на стене в рамочке висит:

managed code: Code that contains enough information to allow the CLI to provide a set of core services. For example, given an address for a method inside the code, the CLI must be able to locate the metadata describing that method. It must also be able to walk the stack, handle exceptions, and store and retrieve security information.


Если ему следовать, то managed-кода за пределами CLI вообще не существует.

S>Работаете вы на С++ — так и работайте, кто ж вам не даёт?


Встречный вопрос: в топикстарте есть ссылка на бумажку про Dark Silicon, можешь что-нибудь сказать по ней? (Попытаемся вернуться к исходным вопросам)

ГВ>>А то, право слово, такое впечатление, что раз вы что-то для себя выбрали, то все вокруг должны, во что бы то ни стало, признавать однозначное превосходство вашей платформы над другими для всех возможных и невозможных случаев. А если их нет, этих преимуществ по каким-то критериям?

S>Это у вас комплекс такой.

Есть две группы: условно "шарписты" и условно "плюсовики". Плюсовики утверждают, что количество ошибок можно снизить до некритичного уровня (во всяком случае, далёкого от той химеры, про которую рассказывает шарписты). Шарписты чуть не в один голос орут что-то в духе: "это невозможно!" Тут, знаешь, у случайно оказавшегося рядом плюсовика не то, что комплекс, а просто раздвоение личности развиться может: ты видишь суслика? А его нет!

S>Вот, к примеру, в этом топике никто ни разу не высказался про "возможных и невозможных случаев".


Я немного приукрасил, да и мне сейчас лень копаться и предметно восстанавливать контексты, но по общему впечатлению неоднократных столкновений: достаточно только краем фразы зацепить .Net или сказать, что C++ не так уж и плох, как о нём говорят (а не ровён час — вообще сравнить его с C# не в уничижительном контексте), как немедленно прискачут шарписты и сразу загалдят всё своими сайтами, индусами, морями ошибок, тупыми студентами, управляемыми ОС, которые вот-вот захватят мир и т.п.

S>Зато с другой стороны идут какие-то постоянные намёки на некомпетентность С#-девелоперов.


Понимаешь ли в чём нюанс: плюсовики обычно ругают шарп (и не только) за объективные технические недостатки, как, кстати, это происходит и здесь. А шарписты ругают C++ за недостатки программистов. Отсюда получается более или менее одинаковая картина почти любого такого конфликта: плюсовик апеллирует к объективному (технике), тогда как шарпист — к субъективному (человеку). Естественная ответная реакция плюсовика — встречная апелляция к человеку (неправомерно, но по-человечески понять можно). Ну а дальше я раз от раза наблюдаю нечто всё более феерическое. Вон, как здесь уже договорились до того, что аллокатор=гуру, скоро до указателей дойдёте.

Так что, всё закономерно. В вычислениях, у кого тут какой комплекс на самом деле и чем он вызван, можешь поупражняться самостоятельно.

S>Недостатки дотнета от программистов, может быть, и не зависят. Зато вот достоинства С++, на которые вы тут ссылаетесь, почему-то очень сильно зависят от программистов.


Вот, то самое, о чём я выше сказал. Недостатки C++ так же не зависят от программиста, и достоинства дотнета (вернее, комплекса: C#+.Net) не в меньшей степени зависят от программиста.

S>А нам, дотнетчикам, хочется, чтобы от программистов зависело поменьше. Потому что программисты — компонент самый ненадёжный.


Здесь у тебя есть очень серьёзный логический изъян. Попробуй найти его сам.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[22]: Конец нересурсов
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 22.11.11 04:00
Оценка:
Здравствуйте, Klatu, Вы писали:

K>>>Ну а что поделаешь. Прога, которая сломалась потому что (очевидно, глобальное/статическое) поле кто-то обнулил [...]

ГВ>>На этом варианты закончились? Только глобальное/статическое?
K>ну попробуй придумай другой вариант

Слишком длинный список получится.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[24]: Конец нересурсов
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 22.11.11 04:16
Оценка:
Здравствуйте, mrTwister, Вы писали:

ГВ>>Если ты заметил, то я на все случаи свой опыт не экстраполирую. Напротив, я говорю о некорректности таких экстраполяций.

T>Ну ты же говоришь, что мол в реальности этих ошибок почти нет. Я охотно верю, что при разработки продукта силами компактной замкнутой команды педантичных плюсовиков этих проблем не будет. Но, к сожалению, не каждый продукт можно разработать в таком режиме за приемлемые сроки.

Это мои проблемы? Ищите нормальных плюсовиков, или хотя бы не распугивайте тех, кто есть.

ГВ>>Сама по себе управляемость, может быть, не при чём. А вот гарантирование корректности ссылок — очень даже при чём.

T>Ты бы предпочел UB?

Я не знаю, как могла бы выглядеть упомянутая возможность.

ГВ>>Нет, комната стала тёмной по другим причинам. Пафосно выражаясь, C++ — это были те искры, которые позволили найти выход из этой комнаты.

T>Предпочитаю фонарик в виде assert искрам из глаз в виде AV

Аналогично. По сути я рассказал историю о поиске двух ошибок: в managed и в unmanaged. Ошибка в unmanaged — как раз пропущенная проверка инварианта.

ГВ>>Без исходного кода я ничего посоветовать не могу. Если хочешь, свяжись по мылу, может быть, что-нибудь придумаем.

T>А исходный код тебе ничего не даст. Тот код, что упал вполне себе невинен. Проблема в том, что кто-то испортил общий хип. [...]

Короче, исходники ты мне давать не собираешься? Тогда говорить не о чем. И — да, программы на C++ сейчас принято писать как набор раздельно тестируемых компонент.

ГВ>>А... Я подумал про design contracts из FW 4. Ну так assert-ом по сути и спаслись.

T>Ну вот видишь. Ассерт — мощная штука, но его не повесишь на порчу памяти.

Спасибо, рассказал. А то я был не в курсе.

ГВ>>Во-во, знакомо. Ошибка — это только если exception, всё остальное — "так и надо".

T>Не совсем. Ошибка — это несоответствие требованиям. Все остальное — "так и надо".

Вот как раз о неудовлетворении некоторых требований речь и идёт.

ГВ>>>>Да и дамп объектов бы не помог... Если я непонятно написал, то уточню: ключом к решению стало добавление защиты от параллельного доступа. Всё остальное было поисками чёрной кошки из-за приключившегося у меня приступа паранойи.

T>>>В дампе ты бы увидел, что было создано два объекта вместо одного. Дальше все тривиально.

ГВ>>Ничего бы я там не увидел... Да и собственно, я говорил о совершенно других вещах.

T>Почему не увидел? Ты хотел привести пример трудноуловимой с точки зрения плюсовика ошибки. Тебе она кажется трудноуловимой, потому что ты не привык [после слова "привык" остальное можно не читать].

Трудноуловимость связана ещё и с количеством одновременно существующих объектов, временем их жизни... Короче, дампом не отделаешься.

T>Ну вот, например, как ты в windbg для С++ сможешь сдампить все объекты заданного типа? Или все произошедшие в последнее время исключения (очень полезно при разборе говнокода, маскирующего исключения)?


Никак, но оно никогда мне и не требовалось. Кроме редких и довольно давних случаев.

ГВ>>Тоже справедливо. А исходников этого самого чужого кода у меня нет?

T>Исходники есть. Но править ты их не можешь.

Ну смотреть-то могу?

T>>>Это говорит о том, что в С++ проблемы можно получить в любом месте и фраза, что неверная интерпретация памяти бывает только [подставить что-то одно] ложная. Неверная интерпретация памяти может произойти по миллиону причин. И для каждой такой причины можно ответить: "надо делать то-то".

ГВ>>Так и надо делать "то-то".
T>Совершенно верно. То есть другими словами, не надо делать ошибок. Но люди их все равно делают, это данность. В случае с С++ многие такие ошибки оборачиваются большими потерями времени.

Да, правильно, и что? Собственно топик о том, что снова набирают силу аргументы типа Perf/Watt, Perf/Cycle, Perf/Cent. Ы?
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[23]: Конец нересурсов
От: Klatu  
Дата: 22.11.11 04:55
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Здравствуйте, Klatu, Вы писали:


K>>>>Ну а что поделаешь. Прога, которая сломалась потому что (очевидно, глобальное/статическое) поле кто-то обнулил [...]

ГВ>>>На этом варианты закончились? Только глобальное/статическое?
K>>ну попробуй придумай другой вариант

ГВ>Слишком длинный список получится.


Ясно. Значит, придумать ничего вразумительного не смог.
Re[22]: Конец нересурсов
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 22.11.11 07:56
Оценка: +1
Здравствуйте, gandjustas, Вы писали:

ГВ>>Ясное дело, в managed с этим намного лучше: ссылку на объект, к которому моя функция будет обращаться, уже давно обнулили, но специально ради моей функции держат в памяти уже забытую всеми остальными копию. Благодарствую за любезность!

G>Именно. Это позволяет делать unmanaged.
G>Есть еще более коварный вид ошибок. Когда ты сам держишь ссылку, а кто-то другой объект удаляет, считая его ненужным.

Это как раз очень простая ситуация. Врубись: я держу ссылку на объект, предполагая, что он кому-то нужен. Но этот кто-то этот самый объект сейчас "выкидывает". В unmanaged произойдёт "ой" из-за внезапного delete, а в managed — будет тишина и я буду продолжать работать с никому не нужным объектом.

ГВ>>>>1) Нельзя вестись на поводу у дурацких стереотипов, что в AVE всегда виноват unmanaged.

G>>>Ок, докажи обратное. Когда чисто managed код вызывает AVE.
ГВ>>Что — обратное?
G>Дальше написано. Пример когда чисто managed код вызывает ave.

Речь идёт о связке unmanaged + managed. И у меня там всё расписано: я не отрицаю того, что исключение бросит именно unmanaged. Важно, почему он это сделает.

ГВ>>>>2) Managed-код превосходно замаскировал ошибки concurrency и маскировал бы их дальше, если бы именно unmanaged не разорался во всю глотку о том, что что-то пошло не так.

G>>>То есть managed код работал, а unmanaged таки падал? Ведь именно unmanaged не был спроектирован под cuncurrency.
ГВ>>Умничка. Именно дотнетный код — работал. Ну, по вашему же, если эксцепшенов нет, значит код — работает! Возьми с полки пирожок. Ты, кстати, не у конкурентов, часом работаешь? Надо посоветовать, чтобы тебе зарплату подняли. Скажи, эдипов папа посоветовал.
G>Не уходит от вопроса. Ты не написал что были какие проблемы непосредственно в managed, ты сказал что он не так вызывал unmanaged, но сам unmanaged этому никак не противился.

Да банальные проблемы — несколько потоков лезли одновременно к одному и тому же объекту без синхронизации.

G>То есть переписал unmanaged так чтобы не было этих проблема можно было вообще исключить эту проблему.


Там было написано: соответствующая проверка была убрана ради оптимизации.

ГВ>>>>3) Если бы не unmanaged, поиски тщательно замаскированной ошибки стали бы для нас чем-то вроде специальной олимпиады: главное не победа, главное — держаться подальше;

G>>>Без unmanaged скорее всего косяк был бы найден раньше ибо в managed из unmanaged не попадет сведений о threading model вызываемого кода.
ГВ>>Без unmanaged ошибка не была бы найдена вообще. Но она от этого никуда бы не делась
G>А в чем тогда ошибка? И почему она не была бы найдена? Или ты что-то не договариваешь ил просто пытаешься свалить вину.

Скажем так: unmanaged создавал некий объект, который передавался в managed, читал он его из некоей большой-пребольшой базы данных (действительно большой, но это к делу не относится). Один вызов unmanaged — один новый объект. В дальнейшем эти объекты с данными поочерёдно помещались в поле объекта-получателя и юзались как read-only (до следующей транзакции). Грубо где-то так:

public class SomeDataProcessing {

  // Текущая порция данных
  SomeData portion;

  // Чтение данных обращением к unmanaged
  public void readDataPortion() {
    portion = callUnmanagedCode();
  }

  // Цикл обработки. Работает в отдельном потоке.
  public void processData() {
    while(...) {
      readDataPortion();
      
      // Обработка того, что положили в portion:
      int a = portion.prop1;
      int b = portion.prop2;
      // ...
    }
  }
}


То есть вызывающему коду было без разницы, в скольки потоках работать — данные он не модифицирует, только читает. И если чтение вдруг происходит в два потока, то один из полученных объектов пропадает (portion-то у нас одно, правильно?), и оба обратившихся потока будут пользоваться ссылкой на один объект данных. Но никаких конфликтов в managed-коде эта ситуация не вызовет. Разве что когда-то потом могло быть отслежено нарушение целостности данных... Но это же ещё надо сначала это нарушение обнаружить, а для этого нужно создать специфичные условия, чтобы два потока создались вместо одного, а в тестовых условиях всё тихо.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[23]: Конец нересурсов
От: Sinclair Россия https://github.com/evilguest/
Дата: 22.11.11 08:18
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:


ГВ>Это как раз очень простая ситуация. Врубись: я держу ссылку на объект, предполагая, что он кому-то нужен. Но этот кто-то этот самый объект сейчас "выкидывает". В unmanaged произойдёт "ой" из-за внезапного delete, а в managed — будет тишина и я буду продолжать работать с никому не нужным объектом.

А можно поподробнее мне объяснить, за счёт чего произойдёт этот "ой"?
Вот я обращаюсь int a = p->m_InstanceCount. Понятное дело, что никаких AV я не дождусь — AV работают только если я далеко промахнулся мимо памяти программы. А тут всё по прежнему в пределах хипа, всё в порядке.
Прочитал я себе целую переменную и пошёл хреначить дальше. Продолжу работать с чем-то другим — 0xDEADBEEF если повезло, или, скажем, с 0, если не повезло и в это место распределился совершенно другой объект. Всё выглядит нормально, только глючит неестественным образом.

Или, ещё лучше, я пишу p->m_InstanceCount--. Кто ж его знает, что я там такое декрементировал?
За счёт какой магии я получу "ой", и в чём он выразится?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[24]: Конец нересурсов
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 22.11.11 08:37
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>А можно поподробнее мне объяснить, за счёт чего произойдёт этот "ой"?

S>Вот я обращаюсь int a = p->m_InstanceCount. Понятное дело, что никаких AV я не дождусь — AV работают только если я далеко промахнулся мимо памяти программы. А тут всё по прежнему в пределах хипа, всё в порядке.

Ну а теперь, давай сделаем простую индукцию. Код принципиально рассчитан на работу в одном потоке, следовательно, хитрых смарт-пойнтеров в нём делать не будут. Просто ни к чему. А значит, вызывающий код с некоторой очень ненулевой вероятностью будет выглядеть примерно так:

void processData() {
  while(...) {
    delete m_pData; // <- вот тут и будет "ой"
    m_pData = callReadingCode();
    int x = m_pData->prop1;
    // ...
  }
}


Может быть, какой-то смарт-пойнтер, конечно и будет на случай исключений, но без особых наворотов.

S>Прочитал я себе целую переменную и пошёл хреначить дальше. Продолжу работать с чем-то другим — 0xDEADBEEF если повезло, или, скажем, с 0, если не повезло и в это место распределился совершенно другой объект. Всё выглядит нормально, только глючит неестественным образом.


На практике чаще всего выстреливается сообщение о развале хипа.

S>Или, ещё лучше, я пишу p->m_InstanceCount--. Кто ж его знает, что я там такое декрементировал?

S>За счёт какой магии я получу "ой", и в чём он выразится?

За счёт разваливания разметки динамической памяти (хипа). Да-да, ты не ослышался.

P.S.: Ой, что сейчас начнётся...
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[21]: Конец нересурсов
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 22.11.11 08:52
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Заблуждение. Если бы отлавливались при тестировании, их бы не было. А по факту на сегодня я не видел еще ни одной достаточно большой дотнетной неглюкавой программы. Хреново в дотнете со статикой-то, а в динамике не всё поймаешь, бесконечным и дейтсвительно всеобъемлющим тестирование не бывает, это миф, бо такое тестирование на пару порядков обойдется дороже собственно разработки.


А у меня их и нет. IndexOutOfRange уже забыл когда получал, NRE в продакшене был крайний раз года два назад.
Причем тупо потому что не использую for, и не передаю null (это контрактами проверяется).

Тестирование позволяет гораздо более сложные ошибки выловить.


T>>>>Не забывай про concunrrncy. Если будет ошибка в синхронизации в управляемом коде, то испортятся только те данные, которые непосредственно участвуют в алгоритме.

V>>>Какая разница, если спустя пол-часа в другом месте получим out of range или null reference?
G>>Стектрейс, хотя для nre в продакшене надо сильно постараться

V>Не льсти себе. Тебя послушать как в дотнете, то "надо просто контрактами обложить", а как в С++, то "обязательно нарушат контракт". Эдак можно много до чего договориться.

См выше. Я не пытаюсь льстить, это прерогатива C++ников, я только привожу свои наблюдения.

V>По моим наблюдениям за глюкавостью дотнетных программ, они ловятся на совершенно детских тестах: например часто при попытке сохранить файл в директорию, защищенную от записи или почти в 100% случаев, при исчерпании какого-нить ресурса (кол-ва сокетов, поверхностей для рисования, свободного места на диске). Такое ощущение, что дотнетчики поголовно пишут код из расчета "всё будет хорошо", проверяя максимум контракты на входные параметры методов, во всех остальных случаях тупо плюя эксепшен, который (удивительно!) никто нигде не ждет.

Так это же прекрасно, если вылетит exception то его быстрее поправят чем если он не вылетит. Писать в стиле let it crash полезно даже для десктопа, потому что позволяет быстро повесить обработку exception на верхнем уровне и выдавать пользователю адекватное сообщение.

V>Понятие безопасного к исключениям кода — это нечто из другой реальности,\

Именно, так как в .NET exception может вылететь где угодно. Пытаться писать код который не кидается исключениями — слишком затратно и абсолютно бесполезно.

V>отсюда дотнет — просто рассадник наведенных ошибок (по опыту своей помощи в ловле ошибок коллег), бо после первой же обработанной (якобы обработанной) ошибочной ситуации, отваливается работоспособность в другом месте, потому как один или несколько объектов остаются в некоем промежуточном невалидном состоянии.

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

V>И хоть подобные ошибки от платформы не зависят, но почему-то дотнетные программы болеют ими чаще, по моим сугубо личным наблюдениям.

Да, тупо порог вхождения ниже. И это прекрасно, .NET позволяет создавать достаточно хорошие продукты с меньшими затратами в среднем.

V>Да, "вы" правы, на плюсах в среднем приходится быть малость внимательней, чем на дотнете, но зато типичных детских ошибок вижу всяко поменьше. ИМХО, от рабочего настроя тоже кое-что зависит. А в дотнет диктует некий расслабон (даже по собственным ощущениям, в сравнении с писаниной на плюсах).

Это смотря то считать типичной ошибкой. Самая типичная ошибка с C++ которую я видел — обращение по невалидному указателю, которое вызывает в лучшем случае AV по месту вызова, а в худшем — перезапись стека или других объектов (наведенная ошибка). Для делфи напрмиер типичная ошибка — неосвобождение памяти, 95% программ на делфи, что я видел, текли. Для .NET типчная ошибка — возврат null и отсутствие проверки, то в худшем случае приводит nre где-то в другом методе.

V>>>Наоборот, в дотнете никакой статической типобезопасноти, в сравнении с С++, где мы задешево можем создавать легковесные шаблонные решения/обертки, которые проталкивают больше прикладной логики в систему типов программы. А чего только стоил эпический флейм в свое время "as vs is" в дотнете? Для сознательной неверной реинтерпретации памяти в С++ надо хачить типобезопасность через приведение в стиле С, или через reinterpret_cast. Но эти же самые приемы мне доступны в точно такой же шаговой доступности в дотнете в unsafe, так что...

G>>Вот только по-умолчанию C# рождает safe код, а unsafe без необходимости даже не ошибка, а вредительство. С++ имеет тяжелое наследие C и не наказывает за попытки писать в стиле С, то есть любой код по умолчанию — unsafe.

V>А как меня наказвают за исопльзование unsafe в дотнете, не пояснишь?

1 )Компилятор по умолчанию запрещает
2) Без fulltrust не работает
3) В некоторых реализациях .NET просто отсутствует

V>И почему хак типов в стиле C есть на твой взгляд "нормально"?

Потому что так пишут.


G>>Использование только safe части C++ делает программу не быстрее (а зачастую и медленнее) чем .NET


V>Стоило бы просить обосновать, но вряд ли справишься. По моим наблюдениям — ровно наоборот, чем больше типизированной информации у компилятора, тем агрессивнее оптимизация.

Только компилятор C++ может использовать такую информацию только в шаблонах. В других местах он бессилен, слишком нестрогая семантика досталась в наследство от C.

V>И да, safe С++ не означает только библиотеки STL. Это просто типизированный подход, например, набивший оскомину выход за пределы массива на стеке, стиле С это так:

V>
V>void doSomething(char * array, size_t size);

V>char array[N];
V>doSomething(array, sizeof(array)); // вот здесь могут подать не тот sizeof в результате многих актов рефакторинга
V>

V>В С++ стиле это будет так:
V>
V><size_t size>
V>void doSomething(char (&array)[size]);

V>char array[N];
V>doSomething(array); // теперь типобезопасно
V>


Совершенно бесполезный пример. Я вот порылся в своих проектах и знаешь сколько у меня массивов с фиксированным на момент компиляции числом элементов? Я насчитал ровно 3 за полгода.
Даже не буду считать насколько ничтожный выйгрыш типа_безопасность даст с таком случае если даст еще.

V>>>Мое ИМХО такое, что дотнет помогает избежать ошибки уровня "утекли ресурсы" или "вышли за границы диапазона"... Это совсем детские ошибки

G>>Ага, только они очень часто встречаются в unmanaged.
V>В сравнении с остальными ошибками, в т.ч. логическими — не видно и под микроскопом. Какая разница, падает программа или неверно работает? Лажа в обоих случаях.
Ты еще не учел что такие ошибки могут приводить к проблема безопасности: повышение привелегий, раскрытие информации, отказ в обслуживании.


V>>>всерьез обсуждать которые мне откровенно лень, потому как есть тот же RAII

G>>Которым далеко не все пользуются

V>Ну я же говорил.

V>Рассуждая так, и контракты в C# мало кто проверяет, это же прямо такое "хакерство" (С).
Контрактами в .NET пользуются еще меньше, чем RAII, но это другой уровень проверок и гарантий.
90% raii уже выполняет clr, ему не хватает только escape-анализа для idisposable объектов чтобы явно не писать using.

V>>>и размер даже обычного массива на стеке может быть передан как автовыводимый в месте вызова параметр шаблонной ф-ии

G>>Ну это когда размер известен на этапе компиляции.

V>Дык, а в других случаях самописанина ничего не дает в сравнении со стандартными контейнерами. Да и эскалацию привилегий ты при проходе по куче не получишь (по стеку надо идти, чтобы передать куда надо управление в текущем кольце), т.е. не получится той самой дырки в безопасности и обсуждать сразу нечего.

Почитай Secure Code, там описано какие уязвимости несет проход по куче. Кроме эскалации привилегий есть еще проблемы.



V>>>что совершенно невозможно в дотнете

G>>Поправочка: не нужно, там массив таскает с собой размер. А умный jit выкидывает проверки границ для циклов от нуля до length-1.
V>Это если мы по всему массиву итерируем, а если нет, то лишней проверки не избежать. Уже обсуждали 4 года назад.
Да, тогда получается дешевле сделать копию и бегать по ней. А там где performance нужен можно бегание по массиву переписать на C. Те же 4 года назад обсуждали.


V>>>Или как можно выйти за границы диапазона при использовании итераторов C++, например? Да никак.

G>>v.end()++ не?

V>Не. Кто мешает мне компилируемую бредятину и на C# писать с тем же успехом?

V>Чем не коровья лепешка?
V>
V>int SomeProp { 
V>  get { return _someProp; } 
  
V>  set {
V>    _somePtrop = value;

V>    if((new Random()).Next() < 0.5)
V>      onSomePropChanged(this, EmptryArgs.Value);
V>  }
V>}
V>

то что ты пишешь — называется вредительством, а код вроде for(auto i = v.begin(); i<=v.end(); i++) { } вполне можно и неспециально написать.
В .NET будет outofrange, а в C++ что? Heap Corruption?


G>>Кроме того даже если ты напишешь safe код, то менее грамотный коллега напишет unsafe, который заставит твой код работать неправильно.


V>Менее грамотный, это год работы. Кто ж ему даст весь код трогать? В любом проекте при хоть какой-то организации полно изолированных мест, где могут разгуляться разработчики любого уровня. Ну и code review определенно рулит.

Code Review не отменяет недостатки языка.
Re[23]: Конец нересурсов
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 22.11.11 09:05
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Это как раз очень простая ситуация. Врубись: я держу ссылку на объект, предполагая, что он кому-то нужен. Но этот кто-то этот самый объект сейчас "выкидывает". В unmanaged произойдёт "ой" из-за внезапного delete, а в managed — будет тишина и я буду продолжать работать с никому не нужным объектом.


Да, и managed программа будет работать и работать корректно. В unmanaged в лучшем случае упадет. Разницу понимаешь?

ГВ>>>>>2) Managed-код превосходно замаскировал ошибки concurrency и маскировал бы их дальше, если бы именно unmanaged не разорался во всю глотку о том, что что-то пошло не так.

G>>>>То есть managed код работал, а unmanaged таки падал? Ведь именно unmanaged не был спроектирован под cuncurrency.
ГВ>>>Умничка. Именно дотнетный код — работал. Ну, по вашему же, если эксцепшенов нет, значит код — работает! Возьми с полки пирожок. Ты, кстати, не у конкурентов, часом работаешь? Надо посоветовать, чтобы тебе зарплату подняли. Скажи, эдипов папа посоветовал.
G>>Не уходит от вопроса. Ты не написал что были какие проблемы непосредственно в managed, ты сказал что он не так вызывал unmanaged, но сам unmanaged этому никак не противился.

ГВ>Да банальные проблемы — несколько потоков лезли одновременно к одному и тому же объекту без синхронизации.

И что? При обращении к любому объекту надо синхронизироваться чтоли? Или на нем как-то написано? В .NET принято в документации указывать о threadsafety.
Давай конкретику что за unmanaged был и что с ним managed делал?

G>>То есть переписал unmanaged так чтобы не было этих проблема можно было вообще исключить эту проблему.

ГВ>Там было написано: соответствующая проверка была убрана ради оптимизации.
Ага, "ради оптимизации" теперь отмазка чтобы писать ненадежный код? Это "ради оптимизации" было зафиксировано в документации? И что вообще код делал?

ГВ>>>>>3) Если бы не unmanaged, поиски тщательно замаскированной ошибки стали бы для нас чем-то вроде специальной олимпиады: главное не победа, главное — держаться подальше;

G>>>>Без unmanaged скорее всего косяк был бы найден раньше ибо в managed из unmanaged не попадет сведений о threading model вызываемого кода.
ГВ>>>Без unmanaged ошибка не была бы найдена вообще. Но она от этого никуда бы не делась
G>>А в чем тогда ошибка? И почему она не была бы найдена? Или ты что-то не договариваешь ил просто пытаешься свалить вину.

ГВ>Скажем так: unmanaged создавал некий объект, который передавался в managed, читал он его из некоей большой-пребольшой базы данных (действительно большой, но это к делу не относится). Один вызов unmanaged — один новый объект. В дальнейшем эти объекты с данными поочерёдно помещались в поле объекта-получателя и юзались как read-only (до следующей транзакции). Грубо где-то так:


ГВ>
ГВ>public class SomeDataProcessing {

ГВ>  // Текущая порция данных
ГВ>  SomeData portion;

ГВ>  // Чтение данных обращением к unmanaged
ГВ>  public void readDataPortion() {
ГВ>    portion = callUnmanagedCode();
ГВ>  }

ГВ>  // Цикл обработки. Работает в отдельном потоке.
ГВ>  public void processData() {
ГВ>    while(...) {
ГВ>      readDataPortion();
      
ГВ>      // Обработка того, что положили в portion:
ГВ>      int a = portion.prop1;
ГВ>      int b = portion.prop2;
ГВ>      // ...
ГВ>    }
ГВ>  }
ГВ>}
ГВ>


ГВ>То есть вызывающему коду было без разницы, в скольки потоках работать — данные он не модифицирует, только читает. И если чтение вдруг происходит в два потока, то один из полученных объектов пропадает (portion-то у нас одно, правильно?), и оба обратившихся потока будут пользоваться ссылкой на один объект данных. Но никаких конфликтов в managed-коде эта ситуация не вызовет. Разве что когда-то потом могло быть отслежено нарушение целостности данных... Но это же ещё надо сначала это нарушение обнаружить, а для этого нужно создать специфичные условия, чтобы два потока создались вместо одного, а в тестовых условиях всё тихо.


Тут получается что просто не договорились между managed и unmanaged о tread safety. Вообще по-умолчанию считается что любой код в .NET не threadsafe, особенно итераторы. Но данный код не совсем итератор и по внешнему виду делать вывод сложно.
Re[24]: Конец нересурсов
От: vdimas Россия  
Дата: 22.11.11 09:07
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

ГВ>>Это как раз очень простая ситуация. Врубись: я держу ссылку на объект, предполагая, что он кому-то нужен. Но этот кто-то этот самый объект сейчас "выкидывает". В unmanaged произойдёт "ой" из-за внезапного delete, а в managed — будет тишина и я буду продолжать работать с никому не нужным объектом.

S>А можно поподробнее мне объяснить, за счёт чего произойдёт этот "ой"?

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

Хотя да, в случае всего одной маленькой переменной не факт, что ты попортишь именно заколовок хипа, а не тело другого объекта. Я тут уже высказывался, что всякого рода шумовые эфекты — это гут, потому что ошибка себя проявляет.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.