Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.144.193.129] |
|
Страницы: (32) « Первая ... 25 26 [27] 28 29 ... 31 32 ( Перейти к последнему сообщению ) |
Сообщ.
#391
,
|
|
|
Цитата Wound @ Нет его программа неправильная. Он неверно оценил время жизни объектов. Представь себе, что чувак написал вместо scope() RAII-обертку, в деструкторе которой вызвал этот свой TTF_Quit(). Все также грохнется без всякого scope().Нет, не с тем же успехом. Если убрать его багу, допустим выкинуть scope(exit) вообще из его программы, никаких сигфолтов нет. Его программа абсолютна правильная и рабочая на языке D. Цитата Wound @ Я хз, как ты оценил багнутость дешной программы с точки зрения C++. Эти языки хоть и сильно похожи, но также и сильно разные. В D можно вообще не освобождать память и утечек не будет, а для C++ утечки будут, и что, эти программы будут багнутые? Бессмыслица какая-то.Но не в С++, вот в этом и состоит существенная разница. Для С++ эта программа багнутая. Именно, вот это главная причина, чувак вступил на теневую территорию, а там легко выстрелить себе в ногу. Аналогично было у меня, когда я попытался перемешать shared_ptr со своими RAII обертками. Это было когда я изучал boost::asio. Забавно, но в относительно сложных системах вроде boost::asio, shared_ptr фактически теряет свою детерминированность и становится очень похож на обычный GC. Очень похоже на вот этот твой пример. Цитата Wound @ Я спорю с тем, что scope(exit) тут не причем. scope(exit) просто выполняет код при выходе из скоупа - все. Если этот код некорректен и приводит к сегфолту, то причем тут сам scope(exit)? Допустим ты написал цикл for в теле которого сделал что-то нехорошее и оно у тебя упало. По твоей логике получается, что цикл for опасен и применять его нужно с осторожностью. Ну я не знаю с чем ты споришь. В Dшном примере - ручное управление ресурсом в перемешку с автоматическим GC. Добавлено Тем что в моей функции нет goto? Цитата Wound @ Возможно и появятся. Ты же нашел экспериментальныек scope в плюсах. Кроме того, еще есть scope(success) и scope(failure).Я думаю, что если бы этот scope(exit) был таким же крутым как RAII, то во всяких Java/C# он давно бы уже был, вместо этих ваших using/try-with-resources, которые имитируют как раз RAII, с принудительным вызовом деструктора. Цитата Wound @ Тут похоже, ты один раз пишешь функцию-обертку, отлаживаешь ее (точно так же как и ты свою RAII-обертку) и используешь много раз не заботясь об освобождении ресурса. Повторю, это не всегда удобнее традиционного RAII.В случае с RAII ты пишешь инициализацию/удаление отдельно, и забыть написать удаление - конечно можно, но это довольно не тривиальная задача. А потом просто юзай и все, не заботясь о том в каком там порядке что у тебя вызывается, или когда там нужно очистить если исключение произошло или еще что то, сам компилятор за тебя все очистит правильно и гарантированно в нужном порядке. Я ничего не имею против RAII и сам им актовно пользуюсь. Но я привожу примеры, где scope(exit) проще и понятнее и не менее безопасно, чем RAII. Вы же мне в ответ приводите другие примеры, где RAII уместнее. Получается странный и бестолковый спор. Добавлено Ну и наконец. Прошу все же учесть, что scope(...) это не только про RAII. scope это скорее про try/catch/finally. Вот коротенькая глава из книжки по D о скоупах, если интересно: http://ddili.org/ders/d.en/scope.html |
Сообщ.
#392
,
|
|
|
Цитата applegame @ Нет его программа неправильная. Он неверно оценил время жизни объектов. Представь себе, что чувак написал вместо scope() RAII-обертку, в деструкторе которой вызвал этот свой TTF_Quit(). Все также грохнется без всякого scope(). Ну как не правильная, я же говорю не про текущий пример, а вообще выкинь scope(exit) - его программа правильная, я имею ввиду что ему не нужно вызывать потом delete a; т.к. у него есть GC, соответственно он на него и положился. В случае с С++ такой ситуации не будет, потому что не будет scope(exit), вместо него будет своя RAII обертка. Далее ресурс который должен уничтожиться до scope(exit) - будет агрегатом этой RAII обертки. Цитата applegame @ Я хз, как ты оценил багнутость дешной программы с точки зрения C++. Эти языки хоть и сильно похожи, но также и сильно разные. В D можно вообще не освобождать память и утечек не будет, а для C++ утечки будут, и что, эти программы будут багнутые? Бессмыслица какая-то. А что там оценивать? Вот смотри: import std.stdio; struct De { ~this() { writeln("De"); } } void main() { auto a = new De(); } Тут есть ошибки, если писать на D? В С++ в таком виде есть ошибка, а в D? Цитата applegame @ Именно, вот это главная причина, чувак вступил на теневую территорию, а там легко выстрелить себе в ногу. Аналогично было у меня, когда я попытался перемешать shared_ptr со своими RAII обертками. Это было когда я изучал boost::asio. Забавно, но в относительно сложных системах вроде boost::asio, shared_ptr фактически теряет свою детерминированность и становится очень похож на обычный GC. Очень похоже на вот этот твой пример. Я что то не понял, в чем ошибка? У shared_ptr есть своя болезнь с циклическими ссылками. Цитата applegame @ Я спорю с тем, что scope(exit) тут не причем. scope(exit) просто выполняет код при выходе из скоупа - все. Если этот код некорректен и приводит к сегфолту, то причем тут сам scope(exit)? Допустим ты написал цикл for в теле которого сделал что-то нехорошее и оно у тебя упало. По твоей логике получается, что цикл for опасен и применять его нужно с осторожностью. Ну как не причем? Представь его бы не было. Как бы ты все это писал? Естественно на RAII каком нить, и у тебя такой ситуации просто не возникло бы. Вот возьми goto - чем он плох? Он такой же как return/continue/break/for/while/etc, он ничем не хуже этих операторов. Но его почему то все ругают. А потому что если им увлечься, то ты будешь писать "как проще", но совсем не "качественно", да вон даже отмотай на 5 страниц назад. Чувак пишет - накой мне писать и городить классы и какие то обертки, если я взял вызвал goto clean: и все. 10 букв, против целого класса!!! Так же и с этим. Тебе не нужно думать и замарачиваться каким то обертками, ты взял вот тут юзнул scope(exit), а в другом месте забыл его вызвать. И вуаля. Цитата applegame @ Тем что в моей функции нет goto? Т.е. по сути твой пример со scope(exit) ничем не отличается от того же goto ? Замени scope(exit) на goto clean: в функции PQExec, да или вообще просто чем вот это: Result exec(...) { auto res = PQExec(...); scope(exit) PQClear(res); ... return Result(res); } auto res = exec(...); Отличается вот от этого: Result exec(...) { auto res = PQExec(...); Result result(res); PQClear(res); ... return result; } auto res = exec(...); ??? Цитата applegame @ Возможно и появятся. Ты же нашел экспериментальныек scope в плюсах. Да потому что в плюсы тащат в последнее время то, что нафиг не уперлось, всякий шлак тупо. Цитата applegame @ Тут похоже, ты один раз пишешь функцию-обертку, отлаживаешь ее (точно так же как и ты свою RAII-обертку) и используешь много раз не заботясь об освобождении ресурса. Чем это от Сишной какой нибудь функции отличается? Хорошо, вот есть у тебя файловый ресурс, покажи как ты это реализуешь? Открыть файл, почитать его, потом что то поделать с вычитанными данными, потом снова почитать, потом записать в него, потом почитать из него, потом закрыть его. Через запятую перечислены отдельные операции, каждая операция - отдельная функция. Потом все это нужно сделать в 10 различных местах. Покажи как мне это сделать со scope(exit)? Добавлено Цитата applegame @ Но я привожу примеры, где scope(exit) проще и понятнее и не менее безопасно, чем RAII. Вы же мне в ответ приводите другие примеры, где RAII уместнее. Получается странный и бестолковый спор. Я тебе об этом писал еще раньше: Цитата Wound @ Важно то, что тот контекст в котором ты говоришь, что якобы удобно писать scope(exit) вот тут - это удобно при твоей архитектуре приложения и удобно в том языке, в котором ты пишешь. Т.е. это не фича, что без нее вот тут будет плохо, это просто ты так написал свою программу. Я например напишу так, что в scope(exit) не будет никакого смысла, другой напишет так, что без goto не обойдешься. Все верно, ты просто выдумываешь примеры причем на D, где уместно будет юзнуть scope(exit), но в С++ - это же будет называться костылем. Тебе об этом как бы и пишут. Цитата applegame @ Ну и наконец. Прошу все же учесть, что scope(...) это не только про RAII. scope это скорее про try/catch/finally. Вот коротенькая глава из книжки по D о скоупах, если интересно: Тото и оно, что все эти try/catch/finally - как раз и являются костылями в языках с GC, потому что там нельзя гарантировать вызов деструктора в определенное время и в определенном месте. Поэтому там просто без try/catch/finally - ты не сможешь нормально писать программу. Даже файл не закроешь нормально. А в С++ это нафиг не нужно, потому что там есть деструкторы. И об этом я тебе тоже писал: Цитата Wound @ Это как знаешь, сказать в C#/Java есть ах**наая плюшка finally, а в С++ ее нет, бе бе бе. Вы мудохайтесь там теперь и живите с этим, а я finally юзаю и доволен. Ну как то вот так это выглядит |
Сообщ.
#393
,
|
|
|
Цитата Wound @ Ну напиши в scope(exit) вместо TTF_Quit(), witeln("Hello, world") и тоже все будет норм. Ты реально не понимаешь, что проблема вот в этом лишнем TTF_Quit(), а не в scope(exit)?Ну как не правильная, я же говорю не про текущий пример, а вообще выкинь scope(exit) - его программа правильная, я имею ввиду что ему не нужно вызывать потом delete a; т.к. у него есть GC, соответственно он на него и положился. Цитата Wound @ В D нет ошибки, продолжай свою мысль.Тут есть ошибки, если писать на D? В С++ в таком виде есть ошибка, а в D? Цитата Wound @ Тем, что во втором варианте, в случае возникновения исключения между auto res = PQExec(...) и PQClear(res), последний не будет вызван и получится утечка. А в первом PQClear(res) будет вызвн в любом случае. Может это то самое отличие от goto, о котором ты спрашиваешь?Т.е. по сути твой пример со scope(exit) ничем не отличается от того же goto ? Замени scope(exit) на goto clean: в функции PQExec, да или вообще просто чем вот это: Result exec(...) { auto res = PQExec(...); scope(exit) PQClear(res); ... return Result(res); } auto res = exec(...); Отличается вот от этого: Result exec(...) { auto res = PQExec(...); Result result(res); PQClear(res); ... return result; } auto res = exec(...); ??? Цитата Wound @ Да в последнее время вообще придумывают всякий шлак вроде C#. Да потому что в плюсы тащат в последнее время то, что нафиг не уперлось, всякий шлак тупо. Цитата Wound @ Ну давай я тебе напишу кривой аналог с RAII вместо scope(exit) с такими же сегфолтом:Ну как не причем? Представь его бы не было. Как бы ты все это писал? Естественно на RAII каком нить, и у тебя такой ситуации просто не возникло бы. struct TTFGuard { this() { TTF_Init(); } ~this() { TTF_Quit(); } } voiud main() { auto a = new SDL; TTFGuard guard; } Убери TTFGuard guard; И сегфолт пропадет. Прямо как со scope(exit). По-твоему, получается, что RAII опасно и его нужно использовать осторожно? Цитата Wound @ Я не понимаю что ты хочешь от меня услышать. scope(exit) и goto это совершенно разные вещи. goto - безусловный переход, scope вставляет указанный код в конец функции.Чем это от Сишной какой нибудь функции отличается? Цитата Wound @ Во-первых, я не выдумываю, это реальные примеры. Во-вторых, scope(exit) в описываемых мной случаях был бы удобней и в C++, если бы он там был, конечно. Возможно скоро появится , но все равно будет уродливым. Объявлять переменные, которые потом никак явно не используются в коде - какая гадость.Все верно, ты просто выдумываешь примеры причем на D, где уместно будет юзнуть scope(exit), но в С++ - это же будет называться костылем. Тебе об этом как бы и пишут. Цитата Wound @ Ок, так и запишем, Киля считает что try и catch - это костыли для языков с GC и в C++ не нужны. Но на всякий случай, я уточню, ты наверное таки имел в виду только finally, а не try/catch/finally? Тото и оно, что все эти try/catch/finally - как раз и являются костылями в языках с GC, потому что там нельзя гарантировать вызов деструктора в определенное время и в определенном месте. Поэтому там просто без try/catch/finally - ты не сможешь нормально писать программу. Даже файл не закроешь нормально. А в С++ это нафиг не нужно, потому что там есть деструкторы. |
Сообщ.
#394
,
|
|
|
Цитата Wound @ try/catch/finally - как раз и являются костылями в языках с GC Но в Delphi есть finally, но нет GC… |
Сообщ.
#395
,
|
|
|
Цитата Wound @ "в 10 различных местах" - это в разных местах одной функции или что? Приведи лучше свой вариант с RAII (не обязательно c реально существующими названиями классов, можно гипотетически), а я приведу аналог со scope. Хорошо, вот есть у тебя файловый ресурс, покажи как ты это реализуешь? Открыть файл, почитать его, потом что то поделать с вычитанными данными, потом снова почитать, потом записать в него, потом почитать из него, потом закрыть его. Через запятую перечислены отдельные операции, каждая операция - отдельная функция. Потом все это нужно сделать в 10 различных местах. Покажи как мне это сделать со scope(exit)? Добавлено Цитата korvin @ Но в Delphi есть finally, но нет GC… А в D, языке с GC, есть такие же гарантии как и в C++, но finally тоже есть. Правда я не видел, чтобы кто-то его использовал. |
Сообщ.
#396
,
|
|
|
Цитата applegame @ Ну напиши в scope(exit) вместо TTF_Quit(), witeln("Hello, world") и тоже все будет норм. Ты реально не понимаешь, что проблема вот в этом лишнем TTF_Quit(), а не в scope(exit)? Ты точно читал что там на форуме обсуждалось? https://forum.dlang.org/post/kjkdfcnpgdegno...forum.dlang.org У него проблема не в лишнем TTF_Quit, у него проблема в порядке вызовов функций: Цитата I'm currently working on a project and for that I've created a thin OO-wrapper on top of derelict-sdl. However, when I close my app, the program terminates with a segfault. I've managed to track down the source, and found that the destructors of my objects are called AFTER the scope(exit) statements. This causes my program to call TTF_CloseFont() after TTF_Quit(), resulting in a segfault. Гугл перевод: В настоящее время я работаю над проектом, и для этого я создал тонкий OO-упаковщик поверх derelict-sdl. Однако когда я закрываю свое приложение, программа завершается с ошибкой. Мне удалось отследить источник, и обнаружил, что деструкторы моих объектов называются ПОСЛЕ scope(exit). Это заставляет мою программу вызывать TTF_CloseFont () после TTF_Quit (), в результате чего возникает ошибка. Он ожидает что у него отработает деструктор его класса De, в котором он вызывает TTF_CloseFont, а после него scope(exit) - который вызывает TTF_Quit. Но из за того что память под класс он выделил на хипе, у него вызывается сначало scope(exit) с TTF_Quit, а после отрабатывает деструктор класса De, в котором вызывается TTF_CloseFont. Где тут лишний вызов то? Цитата applegame @ В D нет ошибки, продолжай свою мысль. Вот именно. Поэтому ты без задней мысли будешь думать что ошибки у тебя нет. А в плюсах это баг априори. Соответственно ты ничего не будешь ждать, ты напишешь RAII обертку, и бага не будет. Цитата applegame @ Тем, что во втором варианте, в случае возникновения исключения между auto res = PQExec(...) и PQClear(res), последний не будет вызван и получится утечка. А в первом PQClear(res) будет вызвн в любом случае. Может это то самое отличие от goto, о котором ты спрашиваешь? Это же Си, там нет исключений! Если разница только в исключениях, то твоей пример ничем не отличается от сишного кода. А объяснять что подход с RAII лучше, чем Сишный нужно? Или ты и так знаешь? Цитата applegame @ Да в последнее время вообще придумывают всякий шлак вроде C#. И чем же он плох? По моему очень даже хороший ЯП. Цитата applegame @ Ну давай я тебе напишу кривой аналог с RAII вместо scope(exit) с такими же сегфолтом: Ага, багнутый аналог! В С++ там не пишут. Ты один ресурс в обертку обернул, а второй ресурс без обертки юзаешь. Здорово! Цитата applegame @ Убери TTFGuard guard; И сегфолт пропадет. Прямо как со scope(exit). По-твоему, получается, что RAII опасно и его нужно использовать осторожно? Ну хватит а? Хватит писать какую то муть. Ты если оборачиваешь в RAII - Оборачивай все. А то у тебя получается херня какая то. Я тоже могу написать какую нибудь неработающую херню на D и сказать - оцтой какойто, а не ЯП. Цитата applegame @ Я не понимаю что ты хочешь от меня услышать. scope(exit) и goto это совершенно разные вещи. goto - безусловный переход, scope вставляет указанный код в конец функции. Ну а goto делает переход, например в конец функции. Ты представляешь этот scope(exit) - как какую то супер пупер фичу, на деле - это обычный костыль, судя по всему введен в язык исключительно с целью освобождения ресурсов при работе с GC. Это единственно верное его предназначение. Но ты выдаешь его зачем то за какую то конфетку Цитата applegame @ Во-первых, я не выдумываю, это реальные примеры. Во-вторых, scope(exit) в описываемых мной случаях был бы удобней и в C++, если бы он там был, конечно. Возможно скоро появится , но все равно будет уродливым. Объявлять переменные, которые потом никак явно не используются в коде - какая гадость. В описываемых тобой случаях - там где он был бы удобен, он был бы удобен исключительно в качестве костыля. Цитата applegame @ Ок, так и запишем, Киля считает что try и catch - это костыли для языков с GC и в C++ не нужны. И да, в D, языке с GC, такие гарантии есть, как и в C++. Не перевирай, я про try/catch - слова не сказал. Или ты не знаешь что такое try/catch/finally? Цитата applegame @ Но на всякий случай, я уточню, ты наверное таки имел в виду только finally, а не try/catch/finally? Поясняю - я имел ввиду try/catch/finally, а не finally. На всякий случай посоветую тебе, ты прежде чем отвечать на это, загугли про это и почитай что такое finally и как оно используется в языках с GC JAVA/C#. Потом уже отвечай. Я не знаю как там в вашем D, но вообще конструкция try/catch/finally судя по всему родилась где то в Java, И вот этот finally - является не отъемлемой частью try/catch/finally, нельзя его написать без try/catch. Поэтому и называется она try/catch/finally. В C# есть аналогичная конструкция, но там быстро смекнули как этим херово было пользоваться в Java, и у себя сделали конструкцию using(var resource = new Resource()){} Которая по сути при выходе из блока вызывает Dispose, для освобождения ресурсов. В Java посоны плакали, кололись, но продолжали жрать кактус, пока потом в одной из последних версий не ввели свою конструкцию try-with-resources. Цитата korvin @ Но в Delphi есть finally, но нет GC… Так в Delphi деструкторов потому что нет. Добавлено Цитата applegame @ в 10 различных местах" - это в разных местах одной функции или что? Приведи лучше свой вариант с RAII (не обязательно c реально существующими названиями классов, можно гипотетически), а я приведу аналог со scope. Ну посмотри на класс std::fstream - обычная RAII Обертка над FILE* дескриптором. В 10 разных местах я хочу юзать вот эти функции, ну например у меня есть 10 кнопок, и в каждом обработчике я хочу производить вот примерно такие действия, разные и в разной последовательности, допустим в обработчике одной кнопки только читаем, во второй читаем и пишем, в третьей читаем, создаем новый файл в него пишем и т.д.. Т.е. мне нужны какие то функции или что ты там сделаешь, за которыми мне потом не надо подчищать, они же сами все сделают. Вообще не парься, у тебя не получится это сделать со scope(exit), либо получится говно какое то, в итоге ты просто напишешь RAII обертку. Что собственно и требовалось доказать. |
Сообщ.
#398
,
|
|
|
Цитата korvin @ Как это нет, когда есть? То что оно называется гордым словом destructor еще не означает что это аналог привычных плюсовых деструкторов. Уже ломали же копья по этому вопросу. В делфи есть инициализаторы и деинициализаторы. А вся модель конструктор/деструктор основана на некой фабрике объектов. Я тоже могу написать какое нибудь API на плюсах, и гдето там в базовом методе назвать метод Destructor, вместо Release, и че - это деструктором станет в привычном понимании этого слова? |
Сообщ.
#399
,
|
|
|
Цитата Wound @ Ты сам сказал, что если убрать совсем scope(exit), то программа станет корректной. А ведь в этом случае TTF_Quit не будт вызван вообще. Из твоих же слов следует, что вызов TTF_Quit лишний.Он ожидает что у него отработает деструктор его класса De, в котором он вызывает TTF_CloseFont, а после него scope(exit) - который вызывает TTF_Quit. Но из за того что память под класс он выделил на хипе, у него вызывается сначало scope(exit) с TTF_Quit, а после отрабатывает деструктор класса De, в котором вызывается TTF_CloseFont. Где тут лишний вызов то? Чувак по незнанию неверно оценил ситуацию, он написал: Цитата А точнее было бы написатьAFTER the scope(exit) statements Цитата scope(exit) никак не влияет на порядок вызовов деструкторов объектов на куче.AFTER exit from the function scope Цитата Wound @ Напиши scope(exit) delete(ptr) и бага не будет. По-твоему написать целую обертку гораздо проще, чем написать вот эту одну строчку, с учетом того что эта обертка будет использована ровно ОДИН раз?Вот именно. Поэтому ты без задней мысли будешь думать что ошибки у тебя нет. А в плюсах это баг априори. Соответственно ты ничего не будешь ждать, ты напишешь RAII обертку, и бага не будет. Цитата Wound @ Очередной ошибочный вывод. Нет не только в исключениях. Также разница в ранних return, в том что код освобождения ресурса пишется прямо рядом с его захватом (прямо как твой любимый unique_ptr с кастомным деструктром, только гораздо опрятнее), ну и если таких мест несколько, то освобождение ресурсов будет выполнено автоматически в порядке обратном захвату. В сяшке ничего этого нет.Это же Си, там нет исключений! Если разница только в исключениях, то твоей пример ничем не отличается от сишного кода. А объяснять что подход с RAII лучше, чем Сишный нужно? Или ты и так знаешь? Цитата Wound @ Ну так и пример багнутый. В D так не пишут. Чувак один ресурс обернул в scope(exit) а воторой доверил GC. Здорово!Ага, багнутый аналог! В С++ там не пишут. Ты один ресурс в обертку обернул, а второй ресурс без обертки юзаешь. Здорово! Цитата Wound @ Ну хватит а? Хватит писать какую то муть. Ты если оборачиваешь в scope(exit) - Оборачивай все. А то у тебя получается херня какая то.Ну хватит а? Хватит писать какую то муть. Ты если оборачиваешь в RAII - Оборачивай все. А то у тебя получается херня какая то. Цитата Wound @ А ты примерно так и сделал. Притащил какую-то неработающую херню со scope(exit) и сказал - оцтой какойто.Я тоже могу написать какую нибудь неработающую херню на D и сказать - оцтой какойто, а не ЯП. Цитата Wound @ Неверно, scope(...) введен в язык для автоматического вызова кода при выходе из скоупа. А при работе с GC ресурсы обычно освобождаются самим GC. Накой там scope(...)?Ну а goto делает переход, например в конец функции. Ты представляешь этот scope(exit) - как какую то супер пупер фичу, на деле - это обычный костыль, судя по всему введен в язык исключительно с целью освобождения ресурсов при работе с GC. Это единственно верное его предназначение. Но ты выдаешь его зачем то за какую то конфетку Цитата Wound @ Вот годный пример использования scope(...). Нужно сделать подсчет текущих активных и успешных http-запросов в http-сервере:В описываемых тобой случаях - там где он был бы удобен, он был бы удобен исключительно в качестве костыля. auto handleHTTPRequest(...) { activeRequests.atomicIncrement(); scope(exit) activeRequests.atomicDecrement(); scope(success) successRequests.atomicIncrement(); ... if(...) return result1; ... if(...) throw Error1; ... if(...) return result2; ... if(...) throw Error2; ... } Цитата Wound @ Поясняю - я имел ввиду try/catch/finally, а не finally. На всякий случай посоветую тебе, ты прежде чем отвечать на это, загугли про это и почитай что такое finally и как оно используется в языках с GC JAVA/C#. Потом уже отвечай. Я не знаю как там в вашем D, но вообще конструкция try/catch/finally судя по всему родилась где то в Java, И вот этот finally - является не отъемлемой частью try/catch/finally, нельзя его написать без try/catch. Тебя трудно понять, Киля. Ты применяешь какие-то определения, выдавая их за общепринятые и потом тебя не понимают. Видимо ты имеешь в виду конструкцию, которую в C# называют try-catch-finally. Ну так ты опять ошибся, так как finally вполне можно написать без try-catch, а именно try-finally без catch. Цитата Wound @ В таком случае, да. RAII самое то.Ну посмотри на класс std::fstream - обычная RAII Обертка над FILE* дескриптором. В 10 разных местах я хочу юзать вот эти функции, ну например у меня есть 10 кнопок, и в каждом обработчике я хочу производить вот примерно такие действия, разные и в разной последовательности, допустим в обработчике одной кнопки только читаем, во второй читаем и пишем, в третьей читаем, создаем новый файл в него пишем и т.д.. Т.е. мне нужны какие то функции или что ты там сделаешь, за которыми мне потом не надо подчищать, они же сами все сделают. Цитата Wound @ Ты привел пример, в котором RAII вполне уместен. Но я таки напишу специально для тебя все это дело в функциональном стиле без всякого RAII, но со scope(exit), дабы, так сказать, расширить твой и не только твой кругозор Вообще не парься, у тебя не получится это сделать со scope(exit), либо получится говно какое то, в итоге ты просто напишешь RAII обертку. Что собственно и требовалось доказать. // Это функция обертка, вместо RAII-объекта void useFile(F fn)(string name, F fn) { auto file = open(name); scope(exit) close(file); fn(file); } void onClick(data) { // используем обертку useFile("hello.txt", (file) { ... write(file, data); ... data1 = read(file); ... }); } |
Сообщ.
#400
,
|
|
|
Цитата applegame @ Ты сам сказал, что если убрать совсем scope(exit), то программа станет корректной. А ведь в этом случае TTF_Quit не будт вызван вообще. Из твоих же слов следует, что вызов TTF_Quit лишний. Я тебе это говорил в контексте правильности/неправильности такого подхода на плюсах, чтоб обратить твое внимание на GC. Цитата applegame @ Чувак по незнанию неверно оценил ситуацию, он написал: Цитата AFTER the scope(exit) statements А точнее было бы написать Цитата AFTER exit from the function scope scope(exit) никак не влияет на порядок вызовов деструкторов объектов на куче. Он как раз все верно оценил, если я правильно понял что там произошло. Ты же видишь в его примере просто надпись в консоль выводится? У него вывелось: scope exit De De А произошло это из за того, что после выхода из функции - не отработал деструктор De, который написан перед scope(exit), этот деструктор отработал в тот момент, когда GC начал подчищать ресурсы, а ресурсы в его случае он начал подчищать, когда он нажал на кнопку Закрыть. сам по себе scope(exit) - Не влияет на порядок вызовов деструкторов, я нигде не утверждал что он влияет. Но используя этот scope(exit) - можно нарваться вот на такие грабли, как у чувака, вот об этом я и написал. Цитата applegame @ Напиши scope(exit) delete(ptr) и бага не будет. По-твоему написать целую обертку гораздо проще, чем написать вот эту одну строчку, с учетом того что эта обертка будет использована ровно ОДИН раз? Ну да, нахер юзать все эти RAII в плюсах. Вот дебилы, правда? че сложно написать delete ptr - где это нужно. По моему, обертку писать не нужно вообще. Это ты придумал. Я предлагал юзать unique_ptr, если тебе хочется сделать вот именно так, а никак иначе. Цитата applegame @ Очередной ошибочный вывод. Нет не только в исключениях. Также разница в ранних return, в том что код освобождения ресурса пишется прямо рядом с его захватом (прямо как твой любимый unique_ptr с кастомным деструктром, только гораздо опрятнее), ну и если таких мест несколько, то освобождение ресурсов будет выполнено автоматически в порядке обратном захвату. В сяшке ничего этого нет. В Сяшке ровно тот же механизм, только вид с боку. Когда ты юзаешь мой любимый unique_ptr, то это полноценная RAII обертка, и она лишена практически всех недостатков. Например что будет у тебя, если во время выделения ресурса произойдет исключение? Будет очищать ресурс, который не существует? Цитата applegame @ Ну так и пример багнутый. В D так не пишут. Чувак один ресурс обернул в scope(exit) а воторой доверил GC. Здорово! Ну как не пишут, если пишут? Я ж даже ссылку привел на того, кто написал Цитата applegame @ А ты примерно так и сделал. Притащил какую-то неработающую херню со scope(exit) и сказал - оцтой какойто. Ага, с тебя взял пример. Ты же первый начал рассказывать как без него тяжко в плюсах жить Цитата applegame @ Неверно, scope(...) введен в язык для автоматического вызова кода при выходе из скоупа. А при работе с GC ресурсы обычно освобождаются самим GC. Накой там scope(...)? На той же на кой finally в языках с GC существует. Расскажи, как ты закроешь сетевое соединение например по выходу из функции, если объект создается на куче? Да ты же бля напишешь scope(exit), ты уже приводил даже этот пример с PQExec Цитата applegame @ И где тут костыль, даже если это написано на плюсах? Понятия не имею по этому коду ничего не очевидно. Цитата applegame @ Тебя трудно понять, Киля. Ты применяешь какие-то определения, выдавая их за общепринятые и потом тебя не понимают. Видимо ты имеешь в виду конструкцию, которую в C# называют try-catch-finally. Ну так ты опять ошибся, так как finally вполне можно написать без try-catch, а именно try-finally без catch. Ты как раз таки все понял, просто тебе видимо потроллить хочеца. Я слышал в Java его частенько называют именно так. И название идет от полной конструкции. Finally не фигурирует сам по себе. Так что ты тоже ошибся выходит, если цеплятся к словам, как ты любишь Цитата applegame @ Ты привел пример, в котором RAII вполне уместен. Но я таки напишу специально для тебя все это дело в функциональном стиле без всякого RAII, но со scope(exit), дабы, так сказать, расширить твой и не только твой кругозор Угумс, я уже видел похожее на шарпах, когда двухсотстрочная портянка оформлена в подобном виде! Очень удобно Там это к слову очень сильно распространено. Делегаты называется. |
Сообщ.
#401
,
|
|
|
Цитата applegame @ А при работе с GC ресурсы обычно освобождаются самим GC. Обычно — нет. А финализаторы в Java давно признаны слишком проблемными. Поэтому ресурсы нужно использовать с try-with-resources. |
Сообщ.
#402
,
|
|
|
Цитата applegame @ Конечно. RAII - это прекрасная технология, особенно если нужен именно объект владеющий ресурсом. А ты разве не такой пример привел? Цитата А вот в случае когда нужен скоуп владеющий ресурсом, RAII зачастую совершенно излишен. Не согласен, он все равно лучше, чем явный defer/scope(exit). Классический пример скоупа - блокировка. Сравни: std::lock_guard lock(mtx); И mtx.lock(); scope(exit) mtx.unlock(); Цитата Угадай, как функциональщики без всяких RAII управляют, допустим, транзакциями в БД? Транзакции не делал, а для управления ресурсами используется bracket pattern в том же haskell: main = do withFile "foo.txt" ReadMode (\handle -> do ...) И это как раз то, о чем я говорю. Цитата В таком случае вероятность забывания написания scope равна вероятности забывания написания деструктора. Верно. И к этому примеру никаких претензий, это аналог RAII, хотя и с ограничениями. Но ты привел не этот код Именно так сделано в Ruby и Kotlin, например. Да и bracket pattern о том же, по сути. Добавлено Цитата applegame @ Но я привожу примеры, где scope(exit) проще и понятнее и не менее безопасно, чем RAII. Пока у тебя не получилось Цитата scope это скорее про try/catch/finally. Можно согласиться, что defer/scope(exit) лучше finally(хотя и не сильно). Но еще лучше using/with/try-with-resources. Тем, что не нужно каждый раз указывать действие по освобождению. На том же уровне with*-функции. ИМХО, их сложнее "забыть" использовать плюс они реализуются без изменения языка(как и RAII), что тоже плюс. Но RAII выигрывает и у них. Хотя бы тем, что может быть точно так же использован для полей структуры/класса. |
Сообщ.
#403
,
|
|
|
Я бы не стал доверять программе, написанной в нарушение Стандарта и неверно считающей оверхед. Совсем не верно. Вообще.
|
Сообщ.
#404
,
|
|
|
Дык он тоже весь на finally. Там практически ничего без SEH написать невозможно, течь будет из всех
Цитата applegame @ И чем это будет отличаться от классического RAII? Ты ещё не забыл о главном преимуществе scope()ов, за которое радеешь?А зачем так писать? Заворачиваем в функцию и вызываем сколько угодно раз не парясь об освобождении ресурса Цитата applegame @ Вот. Собственно это и есть тот критерий, который оправдано можно закостылить scope()ом... но вдруг и внезапно – скоуп может захотеть владеть разными ресурсами, в разном количестве и с разной стратегией владения. Ну и получите и распишитесь, получили такой маленький упсик. Собственно, всё равно владельцем выступает программист, а скоуп просто выступает в роли послушного исполнителя твоей воли. Ибо дашь ему неверные инструкции, он и исполнит их неверно, а давать приходится постоянно, пусть и одни и те же. В RAII инструкции даются один раз, и они всегда одинаковые. Может быть иногда и не удобно, но всегда надёжно.А вот в случае когда нужен скоуп владеющий ресурсом, RAII зачастую совершенно излишен. Добавлено Не путай с автоматическим контролем и исполнением инвариантов. Исполнение данных тобой инструкций – да, автоматическое. С этим и __attribute__((__cleanup__())) справляется. Интересно, почему его не включали в Стандарт C? Это же так удобно, по твоим словам. |
Сообщ.
#405
,
|
|
|
Цитата Qraizer @ Чтобы далеко не посылать.Я бы не стал доверять программе, написанной в нарушение Стандарта и неверно считающей оверхед. Совсем не верно. Вообще. Первые два load-а читают посимвольно из-за того, что не знают, сколько там данных. Это также вызывает постоянные реаллокации приёмного буфера. Вторые два load-а читают скопом весь файл, заранее сконфигурировав приёмный буфер на требуемый размер. Что-то это мне напоминает... Ах да, std::vector<T> vs T*. Ну разве не прелесть. Добавлено Быстренько налобал правильный тест. Теперь все load-ы читают посимвольно в буфер достаточного размера. Полюбуйтесь: File test1.fil C++ istreambuf_iterator : .......... 6906 us C++ stream::rdbuf : .......... 7737 us (0.89) libc fread : .......... 33049 us (0.21) POSIX read : .......... 2367907 us (0.00) File test2.fil C++ istreambuf_iterator : .......... 13458 us C++ stream::rdbuf : .......... 15141 us (0.89) libc fread : .......... 64100 us (0.21) POSIX read : .......... 4671184 us (0.00) File test4.fil C++ istreambuf_iterator : .......... 29175 us C++ stream::rdbuf : .......... 32303 us (0.90) libc fread : .......... 133641 us (0.22) POSIX read : .......... 9758374 us (0.00) File test8.fil C++ istreambuf_iterator : .......... 60140 us C++ stream::rdbuf : .......... 65874 us (0.91) libc fread : .......... 267079 us (0.23) POSIX read : .......... 19191693 us (0.00) File test16.fil C++ istreambuf_iterator : .......... 117328 us C++ stream::rdbuf : .......... 130321 us (0.90) libc fread : .......... 547789 us (0.21) POSIX read : .......... 38444935 us (0.00) File test32.fil C++ istreambuf_iterator : .......... 243340 us C++ stream::rdbuf : .......... 265980 us (0.91) libc fread : .......... 1090477 us (0.22) POSIX read : .......... 75824446 us (0.00) |