Re[24]: Тенденции языков
От: jazzer Россия Skype: enerjazzer
Дата: 25.05.15 06:28
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


J>>Каким образом? Или речь прерывании потока каким-нибудь хакерством за пределами языка, типа KillThread какой-нибудь? Ну тогда да, против лома нет приема.

S>А что у вас вместо лома? В managed environment даже при аборте потока есть шанс отработать хэндлеры и прибрать за собой ресурсы. В С++ такого просто вообще нет.

Ну то есть это единственный сценарий утечки? Низкоуровневый KillThread сразу после выделения памяти?
Ну ОК, осталось только понять, при чем тут исключения
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[24]: Тенденции языков
От: jazzer Россия Skype: enerjazzer
Дата: 25.05.15 06:33
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

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

J>>А Синклер вон до сих пор, в 2015, спустя 16 лет (!!!), какой-то трэш на эту тему пишет
S>В прошлый раз, когда поднималась тема C++, в первом же взятом открытом проекте мы нашли всё подряд — и выделение на голых malloc (хотя "конечно же все серъёзные проекты используют пулы, арены, и прочие продвинутые стратегии выделения/очистки), и raw pointers, и вызовы delete.

S>Но это да, Синклер виноват в том, что программисты С++ пишут вовсе не так, как о себе думают.


Не надо кивать на открытые проекты. Это феерическое ведь ты написал своими руками: "В С++ основная дупа — в том, что нет сборки мусора, а на динамически созданные объекты раскрутка стека не влияет." и дальше рукопашная работа с памятью, как будто ты о RAII вообще никогда не слышал.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[21]: Тенденции языков
От: hi_octane Беларусь  
Дата: 25.05.15 10:00
Оценка: +1
J>Что значит "надежда на RAII"? Это все равно что "надежда на то, что sin(x) вернет синус, а не косинус"
J>RAII — это же не финализаторы в управляемых языках, которые хз когда позовутся и позовутся ли вообще.
J>Тут все гарантировано самим языком, безо всяких надежд.
Надежда в основном на то что RAII будет достаточно. Порядок свёртки какбы тоже часть RAII, и если он вдруг не устраивает крутись как хочешь. У finally с произвольным кодом гибкости всё-таки больше.

_>>2) можно кидать и ловить любую ерунду, с которой потом фиг поймёшь что делать. Вместе с другими зажравшимися программистами из мира интерпретаторов я уже привык к удобному объекту "исключение", с полями, методами, вот этим всем.

J>Все вменяемые разработчики бросают производные от std::exception аж с 98 года.
И тем не менее в том 98-году не сделали это поведение единственно возможным и ключа компилятора --allowNonC98exceptions что бы приучить старообрядцев к порядку.

_>>3) разные команды используют разные базовые классы для исключений, и ни в стандарте ни в популярных либах нету самого главного — стэк трэйса. В результате на разных платформах и в разных компиляторах нужен разный код для сбора стэктрэйса, котрый вроде как нужно вызывать именно в методе где летело само исключение, потом уже поздно. На MSVC точно было именно так, на GCC чуть легче, на Intel не помню.


J>Во-вторых, "вызывать именно в методе, где летело" означает "вызывать в конструкторе исключения" — именно так все и делают (несколько тем на RSDN было об этом) и никакого лишнего кода в "методе, где летело", не появляется — все спрятано в конструкторе.

Всякие AV или Division By Zero уже вызывают правильный конструктор?

J>То ли дело возвращаемые значения. Так и вижу, как из конструктора/деструктора возвращаются коды ошибок

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

J>Как раз исключения в конструкторах гарантируют, что объект не будет создан в кривом состоянии.

J>При этом RAII прибьет то, что успело создаться к моменту вылета исключения.
И как мне помнится всё ляжет если в процессе прибивания что-то пойдёт ещё более не так.

В общем пока все возражения мне видятся такими же как возражения фанатов .NET когда ругаешь косяки их любимой цацки — "никаких проблем нет а если что-то и есть то в языке полно средств выкрутиться, а значит проблемы нет".
Re[22]: Тенденции языков
От: jazzer Россия Skype: enerjazzer
Дата: 25.05.15 10:41
Оценка: 9 (1)
Здравствуйте, hi_octane, Вы писали:

J>>Что значит "надежда на RAII"? Это все равно что "надежда на то, что sin(x) вернет синус, а не косинус"

J>>RAII — это же не финализаторы в управляемых языках, которые хз когда позовутся и позовутся ли вообще.
J>>Тут все гарантировано самим языком, безо всяких надежд.
_>Надежда в основном на то что RAII будет достаточно. Порядок свёртки какбы тоже часть RAII, и если он вдруг не устраивает крутись как хочешь. У finally с произвольным кодом гибкости всё-таки больше.

Это как посмотреть. Во-первых, RAII работает внутри области видимости try, а finally — снаружи, и поэтому никакого доступа к внутренней области видимости не имеет. Как следствие, все надо вытащить за пределы try — гемор номер раз.
Отсюда сразу вытекает гемор номер два — далеко не все объекты разрешают копирование и/или отложенное конструирование.
Ну и гемор номер три — ты не знаешь внутри finally, что именно отвалилось, и что надо чистить, а что — нет. Так что придется придумывать всякие левые флаги и прочие обходные костыли.
С RAII же у тебя, во-первых, все оказывается внутри try (да и самого try обычно нет, кстати), во-вторых, сработают только те откатные RAII, которые успели сконструироваться к этому моменту — все, что ниже, срабатывать не будет.

J>>Все вменяемые разработчики бросают производные от std::exception аж с 98 года.

_>И тем не менее в том 98-году не сделали это поведение единственно возможным и ключа компилятора --allowNonC98exceptions что бы приучить старообрядцев к порядку.

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

_>Всякие AV или Division By Zero уже вызывают правильный конструктор?


Всякие AV или Division By Zero находятся за пределами языка, это UB.

J>>То ли дело возвращаемые значения. Так и вижу, как из конструктора/деструктора возвращаются коды ошибок

_>Ну я как бы не адепт возвращаемых значений, мне просто кажется что исключения по версии C++ могли бы быть лучше.

Как именно лучше? Критикуя — предлагай.

J>>Как раз исключения в конструкторах гарантируют, что объект не будет создан в кривом состоянии.

J>>При этом RAII прибьет то, что успело создаться к моменту вылета исключения.
_>И как мне помнится всё ляжет если в процессе прибивания что-то пойдёт ещё более не так.

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

_>В общем пока все возражения мне видятся такими же как возражения фанатов .NET когда ругаешь косяки их любимой цацки — "никаких проблем нет а если что-то и есть то в языке полно средств выкрутиться, а значит проблемы нет".


Я пока не вижу реальных возражений, кроме того, что нет стандартизированного базового типа исключения.
Вернее, он есть, но нет запрета им не пользоваться.
finally мне скорее не нравится, чем нравится — я считаю RAII гораздо более удобной вещью, чем finally (см. выше).
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[24]: Тенденции языков
От: Evgeny.Panasyuk Россия  
Дата: 25.05.15 11:04
Оценка:
Здравствуйте, Sinclair, Вы писали:

J>>Каким образом? Или речь прерывании потока каким-нибудь хакерством за пределами языка, типа KillThread какой-нибудь? Ну тогда да, против лома нет приема.

S>А что у вас вместо лома?

Например cancellation points раскручивающие стэк.

S>В managed environment даже при аборте потока есть шанс отработать хэндлеры


А что с finally?

S>и прибрать за собой ресурсы.


В недетерминированном порядке? Да ещё и в другом потоке.
Отредактировано 25.05.2015 11:19 Evgeny.Panasyuk . Предыдущая версия . Еще …
Отредактировано 25.05.2015 11:18 Evgeny.Panasyuk . Предыдущая версия .
Отредактировано 25.05.2015 11:16 Evgeny.Panasyuk . Предыдущая версия .
Re[16]: Тенденции языков
От: antropolog  
Дата: 26.05.15 00:42
Оценка: +1
Здравствуйте, Mamut, Вы писали:


M> % игнорируем ошибки

M> catch fly_out_menu:append_item(panel_flyout_menu, "First Item"),
M> catch fly_out_menu:append_item(panel_flyout_menu, "Third Item"),
M> catch fly_out_menu:append_item(panel_flyout_menu, "Second Item"),
M> catch fly_out_menu:append_item(panel_flyout_menu, separator),

согласен, в ерланге сделано по-человечески, но это не отменяет уродского синтаксиса в мейнстрим языках, и конечно не отменяет провоцирование невалидного стейта в принципе.
Re[20]: Тенденции языков
От: antropolog  
Дата: 26.05.15 00:42
Оценка:
Здравствуйте, MTD, Вы писали:

MTD>И где здесь логика на исключениях?


покажи код
Re[16]: Тенденции языков
От: antropolog  
Дата: 26.05.15 00:48
Оценка: :))
Здравствуйте, MTD, Вы писали:


MTD>Исключения — это исключительные ситуации игнорирование которых делает дальнейшую работу бессмысленной, это если ты вдруг не в курсе.

капитан, капитан, улыбнитесь

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

смешные как раз вы, ты так и не привёл отчего-то рефакторинг "говнокода от adobe" с исключениями. а всё потому что это будет ещё больший говнокод. Вот mamut привёл, молодец, трудно спорить, в эрланге работа с исключениями удобна. В .NET/Java и тем более в C++ — нет.

а ты милок так и не понял, что я тебе хотел показать в примере. А хотел я тебе показать то — что любой вызов метода — потенциально бросает исключение, поэтому любое действие должно быть транзакционно. И с кодом ошибок всё очевидно — где return, надо зачекать состояние логики. Это можно прочекать просто глядя на код. Теперь полюбуйся на свой собственный код и скажи, а тебе тоже Гэндальф зарплату платит?
Re[20]: Тенденции языков
От: antropolog  
Дата: 26.05.15 00:50
Оценка:
Здравствуйте, MTD, Вы писали:

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


A>>бросать исключение.


MTD>Не понял, ты же кричал, что код с исключениями — УГ по определению.


да, ты же не слушаешь собеседника, и не понимаешь, что кто-то УЖЕ УМЕЕТ НЕ ИСПОЛЬЗОВАТЬ исключения, надеюсь ты дойдёшь когда-нибудь до этого уровня понимания. И да, я использую исключения там, где в коде нарушается утверждение, т.к. альтернатива этому только одна — завершение работы приложения.
Re[21]: Тенденции языков
От: MTD https://github.com/mtrempoltsev
Дата: 26.05.15 04:26
Оценка: -1
Здравствуйте, antropolog, Вы писали:

MTD>>И где здесь логика на исключениях?


A>покажи код


Ты как себя чувствуешь? Как из моих слов про то, что у итератора удобно иметь 2 метода вместо 1, ты сделал вывод про логику на исключениях? Давай поделись, как твой интеллект к такому выводу пришел, для этого мне показывать какой-то код совершенно лишнее.
Re[21]: Тенденции языков
От: MTD https://github.com/mtrempoltsev
Дата: 26.05.15 04:30
Оценка:
Здравствуйте, antropolog, Вы писали:

MTD>>Не понял, ты же кричал, что код с исключениями — УГ по определению.


A>да, ты же не слушаешь собеседника


Нет, я слушаю:

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


http://rsdn.ru/forum/philosophy/6056981.1
Автор: antropolog
Дата: 23.05.15


P.S. Далее по тексту — хватит уже демонстрировать детские обиды с попытками унылых оскорблений.
Re[17]: Тенденции языков
От: MTD https://github.com/mtrempoltsev
Дата: 26.05.15 04:38
Оценка:
Здравствуйте, antropolog, Вы писали:

A>смешные как раз вы, ты так и не привёл отчего-то рефакторинг "говнокода от adobe" с исключениями.


Я могу отрефакторить, но за деньги. Давай, например, так — я отрефакторю, выложим два куска кода на голосование, если адобовский код признают лучше я тебе переведу 100 долларов, если нет, то ты мне.

A>Вот mamut привёл, молодец, трудно спорить, в эрланге работа с исключениями удобна. В .NET/Java и тем более в C++ — нет.


Увы, с кодами еще хуже.

A>А хотел я тебе показать то — что любой вызов метода — потенциально бросает исключение, поэтому любое действие должно быть транзакционно.


Ну так я тебе и показал, что код ошибки никак это не решает.

A>И с кодом ошибок всё очевидно — где return, надо зачекать состояние логики.


То есть везде.

A>Теперь полюбуйся на свой собственный код и скажи, а тебе тоже Гэндальф зарплату платит?


У меня все отлично, где транзакционность нужна, она там есть.
Re[15]: Тенденции языков
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.05.15 05:29
Оценка: 14 (3)
Здравствуйте, antropolog, Вы писали:

A>отличный код. супер. реально. теперь попробуй его переделать на исключения. могу дать подсказку, в одних случаях наличие error ведёт сразу к возврату из функции ( это легко заменить на единственный try/catch ), а в других ( примерно с середины твоего кода ) error в некоторых случаях игнорируется, например здесь:

Да, на этот баг указали сразу. Просто терпения писать if(error) после каждой строчки не хватило, поэтому мы имеем код, который иногда добавляет элементы, а иногда — нет.
Точнее, программист решил, что в реальности эти методы "небросающие", т.к. там нечему ломаться. Через десять лет, когда реализацию AppendItem изменят, его наследников ждёт большой сюрприз.

A>здесь любая строка может не отработать, но это игнорируется.

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

A>Покажи теперь как это (это — весь твой код ) будет на исключениях, аххахаха (зловещий хохот ).

Действительно — исключения затрудняют написание конкретно этого кода с ошибками. Чтобы проигнорировать ошибку, программист будет вынужден написать try {} catch(...){}.

Но пример действительно показательный — сплошной бойлерплейт.
Я плохо знаком с функциональными языками, но мне кажется очевидным вариант, при котором и бойлерплейта меньше, и с валидностью всё хорошо.
Что мы тут делаем? Конструируем структуру меню.
Пусть каждая функция возвращает либо узел, либо ошибку. И алгебра достаточно тривиальная — объединение (узел & ошибка) даёт ошибку, объединение (узел & узел) даёт узел.
Если мы хотим проигнорировать ошибку, то нам придётся вручную заматчить ошибку и превратить её в void.
Результатом функции, естественно, тоже является либо ошибка либо меню.
Основная фишка исключений — "неявная передача информации о сбое выше по стеку" — будет прекрасно работать и в таком варианте, потому что так устроена алгебра.

Примерный аналог — NaN в операциях с плавающей запятой. Как только у нас где-то в выражении встретился NaN, он сам распространится выше по стеку вплоть до того места, где мы хотим и готовы его обработать.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[16]: Тенденции языков
От: MTD https://github.com/mtrempoltsev
Дата: 26.05.15 05:57
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Но пример действительно показательный — сплошной бойлерплейт.


Бойлерплейта здесь больше с кодами ошибки — все эти if ... return. С исключениями у нас один блок try, если мы что-то здесь можем обработать или вообще его отсутствие. Что касается молчаливого игнорирования — это явная диверсия. Если добавление элемента в меню операция не обязательная, то должнен быть метод добавления элемента в приставкой Try или что-то в этом роде, который будет сам глотать исключения, тогда у нас с одной стороны и писанины мало и сразу видна логика.
Re[17]: Тенденции языков
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.05.15 06:32
Оценка:
Здравствуйте, MTD, Вы писали:

MTD>Бойлерплейта здесь больше с кодами ошибки — все эти if ... return. С исключениями у нас один блок try, если мы что-то здесь можем обработать или вообще его отсутствие. Что касается молчаливого игнорирования — это явная диверсия. Если добавление элемента в меню операция не обязательная, то должнен быть метод добавления элемента в приставкой Try или что-то в этом роде, который будет сам глотать исключения, тогда у нас с одной стороны и писанины мало и сразу видна логика.

Да, совершенно верно. Данный конкретный код с исключениями выглядит гораздо чище, плюс он "надёжнее" в том смысле, что если в спорном фрагменте что-то упало, мы всё же узнаем об этом где-то выше по стеку.
Проблема решения с исключениями — в том, что к моменту отлова исключения мы находимся в каком-то непонятном состоянии: меню уже перепахано, какие-то элементы добавлены, какие-то нет.
Решительно непонятно, как же вернуться к стабильному состоянию.
immutable и сборка мусора здесь сильно помогли бы: даже если у нас формирование меню было готово на 99%, и упала какая-то финальная операция, то мы возвращаем ошибку, а вся кунсткамера, "созданная" к этому моменту, как будто никогда и не существовала.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[17]: Тенденции языков
От: AlexRK  
Дата: 26.05.15 06:51
Оценка:
Здравствуйте, MTD, Вы писали:

S>>Но пример действительно показательный — сплошной бойлерплейт.

MTD>Бойлерплейта здесь больше с кодами ошибки — все эти if ... return. С исключениями у нас один блок try, если мы что-то здесь можем обработать или вообще его отсутствие.

Если говорить о бойлерплейте, то в данном случае он просто из-за говнокода, а не по вине кодов ошибок.
Я уже писал тут: если классы построены грамотно (код ошибки сидит внутри и проверяется по необходимости), или как предложил Sinclair — с возвратом алгебраического типа, то никакого бойлерплейта не будет — будет вызов цепочки методов, как обычно.
Re[16]: Тенденции языков
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 26.05.15 07:21
Оценка: +1
Здравствуйте, Mamut, Вы писали:

A>>Покажи теперь как это (это — весь твой код ) будет на исключениях


M>
add_to_menu(Item) ->
  try
    fly_out_menu:append_item(panel_flyout_menu, Item)
  catch
    _:Reason -> {error, Reason}
  end.

...


Ага, т.е. исключение первым делом конвертируется в возвращаемое значение вроде растовского Result, и с ним уже дальше вся работа. В Расте будет то же, только без вот этого дополнительного этапа конверсии исключения в Result. Просили код на исключениях, получили код на кодах возврата, по сути.
Re[17]: Тенденции языков
От: MTD https://github.com/mtrempoltsev
Дата: 26.05.15 08:13
Оценка:
Здравствуйте, D. Mon, Вы писали:

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


Да Mamut зачем-то повелся на призыв некоего троля совершать диверсию игнорировать ошибки.
Re[18]: Тенденции языков
От: fddima  
Дата: 26.05.15 08:26
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Если говорить о бойлерплейте, то в данном случае он просто из-за говнокода, а не по вине кодов ошибок.

ARK>Я уже писал тут: если классы построены грамотно (код ошибки сидит внутри и проверяется по необходимости), или как предложил Sinclair — с возвратом алгебраического типа, то никакого бойлерплейта не будет — будет вызов цепочки методов, как обычно.
Никакого говнокода. Код либо будет обрабатывать ошибки — либо нет. С кодами возврата — добавляется лишь только ахеревший рукописный бранчинг на ровном месте и в каждом месте, который ведет преимущественно на выход, как в этом примере. А именно это исключения и дают.

Если класс построен грамотно, — он не будет привносить ненужное состояние к себе внутрь, до тех пор, пока в этом не возникнет реальной необходимости. Какая ошибка внутри класса? Классу то оно зачем? А пользователю класса зачем? Поиметь третюю пару Get(Set)LastError, что б было и было грамотно?

Код разумеется не мой — он отсюда Isolating Microsoft Office Extensions with the COM Shim Wizard Version 2.3, но, теперь, как Мамут, нагло поступил с меню — уже не поступишь. Хотя в принципе, и тут кучу методов можно разложить.

Это конечно по всей видимости не супер код, но и ничего криминального. В сущности нам такой и нужен был.
Я вообще его взял, только потому, что он мне последним попался на глаза.

// stdafx.h
// Ха-ха. На самом деле после этого - дальше можно не смотреть было бы-то, C++-ники называется. :)
#define IfFailGo(x) { hr=(x); if (FAILED(hr)) goto Error; }
#define IfNullGo(p) { if(!p) {hr = E_FAIL; goto Error; } }


Код:
  Скрытый текст
// CLRLoader.cpp
#include "StdAfx.h"
#include "clrloader.h"
#include "metahost.h"  // CLR 40 hosting interfaces

// When loading assemblies targeting CLR 4.0 and above make sure
// the below line is NOT commented out. It enables starting
// CLR using new hosting interfaces available in CLR 4.0 and above.
// When below line is commeted out the shim will use legacy interfaces 
// which only allow loading CLR 2.0 or below.
#define USE_CLR40_HOSTING

#ifdef USE_CLR40_HOSTING
static LPCWSTR g_wszAssemblyFileName =
    L"MyAddin.dll";
#endif

using namespace mscorlib;

static HRESULT GetDllDirectory(TCHAR *szPath, DWORD nPathBufferSize);


CCLRLoader::CCLRLoader(void)
    : m_pCorRuntimeHost(NULL), m_pAppDomain(NULL)
{
}

// CreateInstance: loads the CLR, creates an AppDomain, and creates an
// aggregated instance of the target managed add-in in that AppDomain.
HRESULT CCLRLoader::CreateAggregatedAddIn(
    IUnknown* pOuter,
    LPCWSTR szAssemblyName,
    LPCWSTR szClassName,
    LPCWSTR szAssemblyConfigName)
{
    HRESULT hr = E_FAIL;

    CComPtr<_ObjectHandle>                              srpObjectHandle;
    CComPtr<ManagedHelpers::IManagedAggregator >        srpManagedAggregator;
    CComPtr<IComAggregator>                             srpComAggregator;
    CComVariant                                         cvarManagedAggregator;

    // Load the CLR, and create an AppDomain for the target assembly.
    IfFailGo( LoadCLR() );
    // DebugBreak();
    IfFailGo( CreateAppDomain(szAssemblyConfigName) );

    // Create the managed aggregator in the target AppDomain, and unwrap it.
    // This component needs to be in a location where fusion will find it, ie
    // either in the GAC or in the same folder as the shim and the add-in.
    IfFailGo( m_pAppDomain->CreateInstance(
        CComBSTR(L"ManagedAggregator, PublicKeyToken=d51fbf4dbc2f7f14"),
        CComBSTR(L"ManagedHelpers.ManagedAggregator"),
        &srpObjectHandle) );
    IfFailGo( srpObjectHandle->Unwrap(&cvarManagedAggregator) );
    IfFailGo( cvarManagedAggregator.pdispVal->QueryInterface(
        &srpManagedAggregator) );

    // Instantiate and aggregate the inner managed add-in into the outer
    // (unmanaged, ConnectProxy) object.
    IfFailGo( pOuter->QueryInterface(
        __uuidof(IComAggregator), (LPVOID*)&srpComAggregator) );
    IfFailGo( srpManagedAggregator->CreateAggregatedInstance(
        CComBSTR(szAssemblyName), CComBSTR(szClassName), srpComAggregator) );

Error:
    return hr;
}

#ifdef USE_CLR40_HOSTING

// Convert "vN.N.N" into an array of numbers
static void ParseClrVersion(LPCWSTR wszVersion, int rgiVersion[3])
{
    rgiVersion[0] = rgiVersion[1] = rgiVersion[2] = 0;

    LPCWCH pwch = wszVersion;
    for (int i = 0; i < 3; i++)
    {
        // skip the firtst character - either 'v' or '.' and add the numbers
        for (pwch++; L'0' <= *pwch && *pwch <= L'9'; pwch++) 
            rgiVersion[i] = rgiVersion[i] * 10 + *pwch - L'0';

        if (*pwch == 0)
            break;

        assert ( *pwch == L'.' && L"we should expect a period. Otherwise it is not a proper CLR version string");
        if (*pwch != L'.')
        {
            // the input is invalid - do not parse any further
            break;
        }
    }
}

// compare order of CLR versions represented as array of numbers
static BOOL IsClrVersionHigher(int rgiVersion[3], int rgiVersion2[3])
{
    for (int i = 0; i < 3; i++)
    {
        if (rgiVersion[i] != rgiVersion2[i])
            return rgiVersion[i] > rgiVersion2[i];
    }

    return FALSE;
}

static HRESULT FindLatestInstalledRuntime(ICLRMetaHost* pMetaHost, LPCWSTR wszMinVersion, ICLRRuntimeInfo** ppRuntimeInfo)
{
    CComPtr<IEnumUnknown> srpEnum;
    CComPtr<ICLRRuntimeInfo> srpRuntimeInfo, srpLatestRuntimeInfo;
    ULONG cFetched;
    WCHAR rgwchVersion[30];
    DWORD cwchVersion;
    int rgiMinVersion[3]; //Major.Minor.Build
    int rgiVersion[3]; // Major.Minor.Build
    HRESULT hr = S_OK;

    *ppRuntimeInfo = NULL;

    // convert vN.N.N into an array of numbers
    ParseClrVersion(wszMinVersion, rgiMinVersion);

    IfFailGo( pMetaHost->EnumerateInstalledRuntimes(&srpEnum) );
    while (true)
    {
        srpRuntimeInfo.Release();
        IfFailGo( srpEnum->Next(1, (IUnknown**)&srpRuntimeInfo, &cFetched) );
        if (hr == S_FALSE)
            break;

        cwchVersion = ARRAYSIZE(rgwchVersion);
        IfFailGo( srpRuntimeInfo->GetVersionString(rgwchVersion, &cwchVersion) );

        ParseClrVersion(rgwchVersion, rgiVersion);
        if (IsClrVersionHigher(rgiVersion, rgiMinVersion) == FALSE)
            continue;

        rgiMinVersion[0] = rgiVersion[0];
        rgiMinVersion[1] = rgiVersion[1];
        rgiMinVersion[2] = rgiVersion[2];

        srpLatestRuntimeInfo.Attach(srpRuntimeInfo.Detach());
    }

    if (srpLatestRuntimeInfo == NULL)
    {
        hr = E_FAIL;
        goto Error;
    }

    hr = S_OK;
    *ppRuntimeInfo = srpLatestRuntimeInfo.Detach();

Error:
    return hr;
}

static HRESULT BindToCLR4OrAbove(ICorRuntimeHost** ppCorRuntimeHost)
{
    HRESULT hr;
    CComPtr<ICLRMetaHost> srpMetaHost;
    CComPtr<ICLRRuntimeInfo> srpRuntimeInfo;
    WCHAR rgwchPath[MAX_PATH + 1];
    WCHAR rgwchVersion[30];
    DWORD cwchVersion = ARRAYSIZE(rgwchVersion);

    *ppCorRuntimeHost = NULL;

    IfFailGo( CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (void**)&srpMetaHost) );

    // Get the location of the hosting shim DLL, and retrieve the required
    // CLR runtime version from its metadata
    IfFailGo( GetDllDirectory(rgwchPath, ARRAYSIZE(rgwchPath)) );
    if (!PathAppend(rgwchPath, g_wszAssemblyFileName))
    {
        hr = E_UNEXPECTED;
        goto Error;
    }
    IfFailGo( srpMetaHost->GetVersionFromFile(rgwchPath, rgwchVersion, &cwchVersion) );

    // First try binding to the same version of CLR the add-in is built against
    hr = srpMetaHost->GetRuntime(rgwchVersion, IID_ICLRRuntimeInfo, (void**)&srpRuntimeInfo);
    if (FAILED(hr))
    {
        // If we're here - it means the exact same version of the CLR we built against is not available.
        // In this case we will just load the highest compatible version
        srpRuntimeInfo.Release();
        IfFailGo( FindLatestInstalledRuntime(srpMetaHost, rgwchVersion, &srpRuntimeInfo) );
    }

    // we ignore the result of SetDefaultStartupFlags - this is not critical operation
    srpRuntimeInfo->SetDefaultStartupFlags(STARTUP_LOADER_OPTIMIZATION_MULTI_DOMAIN_HOST, NULL);

    IfFailGo( srpRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_ICorRuntimeHost, (void**)ppCorRuntimeHost) );

Error:
    return hr;
}

#endif

// LoadCLR: loads and starts the .NET CLR.
HRESULT CCLRLoader::LoadCLR()
{
    HRESULT hr = S_OK;

    // Ensure the CLR is only loaded once.
    if (m_pCorRuntimeHost != NULL)
    {
        return hr;
    }

#ifdef USE_CLR40_HOSTING
    hr = BindToCLR4OrAbove(&m_pCorRuntimeHost);
#else

#pragma warning( push )
#pragma warning( disable : 4996 )
    // Load the CLR into the process, using the default (latest) version,
    // the default ("wks") flavor, and default (single) domain.
    hr = CorBindToRuntimeEx(
        NULL, NULL, STARTUP_LOADER_OPTIMIZATION_MULTI_DOMAIN_HOST,
        CLSID_CorRuntimeHost, IID_ICorRuntimeHost,
        (LPVOID*)&m_pCorRuntimeHost);
#pragma warning( pop )

#endif

    // If CorBindToRuntimeEx returned a failure HRESULT, we failed to
    // load the CLR.
    if (FAILED(hr))
    {
        return hr;
    }

    // Start the CLR.
    return m_pCorRuntimeHost->Start();
}

// In order to securely load an assembly, its fully qualified strong name
// and not the filename must be used. To do that, the target AppDomain's
// base directory needs to point to the directory where the assembly is.
HRESULT CCLRLoader::CreateAppDomain(LPCWSTR szAssemblyConfigName)
{
    USES_CONVERSION;
    HRESULT hr = S_OK;

    // Ensure the AppDomain is created only once.
    if (m_pAppDomain != NULL)
    {
        return hr;
    }

    CComPtr<IUnknown> pUnkDomainSetup;
    CComPtr<IAppDomainSetup> pDomainSetup;
    CComPtr<IUnknown> pUnkAppDomain;
    TCHAR szDirectory[MAX_PATH + 1];
    TCHAR szAssemblyConfigPath[MAX_PATH + 1];
    CComBSTR cbstrAssemblyConfigPath;

    // Create an AppDomainSetup with the base directory pointing to the
    // location of the managed DLL. We assume that the target assembly
    // is located in the same directory.
    IfFailGo( m_pCorRuntimeHost->CreateDomainSetup(&pUnkDomainSetup) );
    IfFailGo( pUnkDomainSetup->QueryInterface(
        __uuidof(pDomainSetup), (LPVOID*)&pDomainSetup) );

    // Get the location of the hosting shim DLL, and configure the
    // AppDomain to search for assemblies in this location.
    IfFailGo( GetDllDirectory(
        szDirectory, sizeof(szDirectory)/sizeof(szDirectory[0])) );
    pDomainSetup->put_ApplicationBase(CComBSTR(szDirectory));

    // Set the AppDomain to use a local DLL config if there is one.
    IfFailGo( StringCchCopy(
        szAssemblyConfigPath,
        sizeof(szAssemblyConfigPath)/sizeof(szAssemblyConfigPath[0]),
        szDirectory) );
    if (!PathAppend(szAssemblyConfigPath, szAssemblyConfigName))
    {
        hr = E_UNEXPECTED;
        goto Error;
    }
    IfFailGo( cbstrAssemblyConfigPath.Append(szAssemblyConfigPath) );
    IfFailGo( pDomainSetup->put_ConfigurationFile(cbstrAssemblyConfigPath) );

    // Create an AppDomain that will run the managed assembly, and get the
    // AppDomain's _AppDomain pointer from its IUnknown pointer.
    IfFailGo( m_pCorRuntimeHost->CreateDomainEx(T2W(szDirectory),
        pUnkDomainSetup, 0, &pUnkAppDomain) );
    IfFailGo( pUnkAppDomain->QueryInterface(
        __uuidof(m_pAppDomain), (LPVOID*)&m_pAppDomain) );

Error:
   return hr;
}

// GetDllDirectory: gets the directory location of the DLL containing this
// code - that is, the shim DLL. The target add-in DLL will also be in this
// directory.
static HRESULT GetDllDirectory(TCHAR *szPath, DWORD nPathBufferSize)
{
    // Get the shim DLL module instance, or bail.
    HMODULE hInstance = _AtlBaseModule.GetModuleInstance();
    if (hInstance == 0)
    {
        return E_FAIL;
    }

    // Get the shim DLL filename, or bail.
    TCHAR szModule[MAX_PATH + 1];
    DWORD dwFLen = ::GetModuleFileName(hInstance, szModule, MAX_PATH);
    if (dwFLen == 0)
    {
        return E_FAIL;
    }

    // Get the full path to the shim DLL, or bail.
    TCHAR *pszFileName;
    dwFLen = ::GetFullPathName(
        szModule, nPathBufferSize, szPath, &pszFileName);
    if (dwFLen == 0 || dwFLen >= nPathBufferSize)
    {
        return E_FAIL;
    }

    *pszFileName = 0;
    return S_OK;
}

// Unload the AppDomain. This will be called by the ConnectProxy
// in OnDisconnection.
HRESULT CCLRLoader::Unload(void)
{
    HRESULT hr = S_OK;
    IUnknown* pUnkDomain = NULL;
    IfFailGo(m_pAppDomain->QueryInterface(
        __uuidof(IUnknown), (LPVOID*)&pUnkDomain));
    hr = m_pCorRuntimeHost->UnloadDomain(pUnkDomain);

    // Added in 2.0.2.0, only for Add-ins.
    m_pAppDomain->Release();
    m_pAppDomain = NULL;

Error:
    if (pUnkDomain != NULL)
    {
        pUnkDomain->Release();
    }
    return hr;
}

CCLRLoader::~CCLRLoader(void)
{
    if (m_pAppDomain)
    {
        m_pAppDomain->Release();
    }
    if (m_pCorRuntimeHost)
    {
        m_pCorRuntimeHost->Release();
    }
}
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[18]: Тенденции языков
От: Evgeny.Panasyuk Россия  
Дата: 26.05.15 15:25
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

S>Решительно непонятно, как же вернуться к стабильному состоянию.

S>immutable

А как бы оно здесь помогло? У нас здесь изначально не-immutable API, которое скорей всего под капотом ещё и дёргает императивные системные вызовы.

S>и сборка мусора здесь сильно помогли бы: даже если у нас формирование меню было готово на 99%, и упала какая-то финальная операция, то мы возвращаем ошибку, а вся кунсткамера, "созданная" к этому моменту, как будто никогда и не существовала.


Сборка мусора более-менее подходит только для памяти, для остальных ресурсов не очень — именно поэтому во многих языках появляются конструкции для scope-based lifetime managmenet, а-ля using в C#, try-with-resources в Java, и with в Python, правда им всем до полноценного RAII далеко.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.