Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.16.81.94] |
|
Страницы: (32) « Первая ... 26 27 [28] 29 30 ... Последняя » ( Перейти к последнему сообщению ) |
Сообщ.
#406
,
|
|
|
Цитата Qraizer @ Чтобы далеко не посылать. Первые два load-а читают посимвольно из-за того, что не знают, сколько там данных. Это также вызывает постоянные реаллокации приёмного буфера. Вторые два load-а читают скопом весь файл, заранее сконфигурировав приёмный буфер на требуемый размер. Что-то это мне напоминает... Ах да, std::vector<T> vs T*. Ну разве не прелесть. Да, надо свое мутить! Хотя есть задачи и по важнее. Например "окроссплатформить" чтение/запись в файл по позиционированию по off_t для x32/64. |
Сообщ.
#407
,
|
|
|
Ну и это я ещё спустил на тормозах const_cast<char*>(std::string::data())
|
Сообщ.
#408
,
|
|
|
Если бы он все верно оценил, он бы так не написал. Очевидно, что он думал, что деструкторы объектов на куче вызываются по тем же правилам, что и деструкторы объектов на стеке.
Цитата Wound @ Ну так они и пишут, в деструкторах оберток и кастомных делетерах unique_ptr.Ну да, нахер юзать все эти RAII в плюсах. Вот дебилы, правда? че сложно написать delete ptr - где это нужно. Цитата Wound @ Нет в сяшке не тот же. Вызовуться только те scope(), которые успели отработать. Поведение scope(exit) в плане очистки ресурсов полностью совпадает с unique_ptr с кастомным деструктором. Похоже, ты не совсем понял оно работает. Вот посмотри очень короткий пример: https://run.dlang.io/is/7jJE7bВ Сяшке ровно тот же механизм, только вид с боку. Когда ты юзаешь мой любимый unique_ptr, то это полноценная RAII обертка, и она лишена практически всех недостатков. Например что будет у тебя, если во время выделения ресурса произойдет исключение? Будет очищать ресурс, который не существует? Он начинающий, очевидно. Представь себе, что новичок, заюзал shared_ptr для некоего обекта. Потом зачем-то в деструкторе какой-нибудь RAII-обертки сделал TTF_Quit, а позже в деструкторе объекта торчащем в shared_ptr вызвался TTF_CloseFont. Сегфолт. Похожим образом я много лет назад облажался с boost::asio. Объект сидящий в boost::shared_ptr (в те времена, еще не было std::shared_ptr) пережил другой объект, без которого он не мог нормально работать. Долго не мог понять что за говно, потом понял и больше так не делал. Ибо нефиг. Цитата Wound @ Ты написал так:сам по себе scope(exit) - Не влияет на порядок вызовов деструкторов, я нигде не утверждал что он влияет. Цитата Wound @ Я это понял так, что ты решил, что scope(exit) как-то влияет на это.Ну и к слову, встречал что если класс в D создавать через new, то порядок вызовов с этим scope(exit) - уже не такой однозначный, а все из за GC, так что даже эта "плюшка" может запросто поломать программу. Цитата Wound @ Ну я не тащил сюда всякие странные багнутые куски кода. А так да, в C++ нет scope, но есть RAII, а в D есть и scope и RAII. Ага, с тебя взял пример. Ты же первый начал рассказывать как без него тяжко в плюсах жить Цитата Wound @ Я не сразу понял. Когда я писал try/catch/finally я имел в виду совокупность всех возможных комбинаций и так же понял и твое try/catch/finally.Ты как раз таки все понял, просто тебе видимо потроллить хочеца. Я слышал в Java его частенько называют именно так. И название идет от полной конструкции. Finally не фигурирует сам по себе. Так что ты тоже ошибся выходит, если цеплятся к словам, как ты любишь Важно понимать, что scope(success)/scope(failure)/scope(exit) похожи на try/catch/finally, но отличия достаточно большие. |
Сообщ.
#409
,
|
|
|
Цитата korvin @ Да, наверное ты прав, обычно нет. Та же фигня и с деструкторами классов в D.Обычно — нет. А финализаторы в Java давно признаны слишком проблемными. Поэтому ресурсы нужно использовать с try-with-resources. Нет не такой. Мне не нужен был объект владеющий ресурсом, мне нужен был сам ресурс. Под объектом в данном случае я подразумеваю не просто владение, но и предоставление интерфейса для работы с этим ресурсом. В моем случае, интерфейс был реализован через сишные вызовы внешних функций и, я не вижу никакого смысла писать обертку даже просто для владения. Результат запроса (указатель на PGresult), возвращаемый из сишной либы, никуда за пределы одной-единственной функции не попадает. Понимаешь? Этот PQClear встречается во всей моей обертке вокруг libpq ровно один раз, а именно в scope(exit) в одном из методов класса Connection. Ты предлагаешь городить RAII-обертку на случай: "а вдрух когда-нибудь мне понадобится работать с PGresult в нескольких разных местах"? Вот когда понадобится тогда и напишу, но скорее не RAII, а в функциональном стиле, так как считаю что писать RAII исключительно для владения - костыль. Но пока не понадобилось, и я более чем уверен что и не понадобится. Цитата D_KEY @ Тут у тебя неверное сравнение. Ты же скрыл код самого std::lock_guard, в котором присутствует такой же mtx.unlock(). Тогда двай уж и scope(exit) вынесем в отдельную функцию:Не согласен, он все равно лучше, чем явный defer/scope(exit). Классический пример скоупа - блокировка. { std::lock_guard lock(mtx); ... } против locked(mtx, { ... }); И знаешь чем второе лучше первого? Нет бесполезного и странно выглядящего для людей не знающих C++ объявления переменной lock, которая нигде потом явно не используется. То самое создание объекта исключительно ради владения ресурсом и без предоставления интерфейса работы с этим ресурсом. Самый что ни на есть настоящий костыль. Цитата D_KEY @ Вообще-то именно такой код я и привел. Более того, только в подобных случаях и уместен scope(exit). Если тебе приходится писать scope(exit) с одним и тем же кодом более одного раза - ты что-то делаешь не так.Верно. И к этому примеру никаких претензий, это аналог RAII, хотя и с ограничениями. Но ты привел не этот код Не знаю что за defer (Go?). А вот scope(...) довольно сильно отличается от finally как синтаксисом так и семантикой. Цитата D_KEY @ Ты просто читаешь тему по диагонали Я с самого начала говорил и несколько раз потом повторил, что scope(...) удобен для однократного использования и он умеет работать с чем угодно, а не только с ресурсами. Даже примеры счетчиков запросов приводил. А ты зациклился на ресурсах и DRY. Давай расциклись уже Но еще лучше using/with/try-with-resources. Тем, что не нужно каждый раз указывать действие по освобождению. Если тебе нужно работать с ресурсом в разных местах, заверни scope(...) в отдельную функцию (получится тот же using/with/try-with-resources, только лучше, потому что гибче) или делай RAII. Цитата D_KEY @ Это как сказать, что вездеход лучше автомобиля, потому что вездеход может быть точно также использован для езды по болотам. Но RAII выигрывает и у них. Хотя бы тем, что может быть точно так же использован для полей структуры/класса. |
Сообщ.
#410
,
|
|
|
Цитата applegame @ Не знаю что за defer (Go?) Да f, err := os.Open("some/file") if err != nil { return err } defer f.Close() и ещё Zig, например const std = @import("std"); pub fn main() !void { const file = try std.fs.cwd().openFile("does_not_exist/foo.txt", .{}); defer file.close(); try file.writeAll("all your codebase are belong to us\n"); } |
Сообщ.
#411
,
|
|
|
Цитата Qraizer @ Тем, что написать такую обертку проще, чем RAII-класс. Ну и в случаях вроде лока мютексов еще и нет бесполезных объявлений переменных. Посмотри на свою иммитацию scope: scope1, scope2, scope3... - что это за мерзкие нумерованные переменные, которые нигде не задействованы? Вот где костыль-то.И чем это будет отличаться от классического RAII? Ты ещё не забыл о главном преимуществе scope()ов, за которое радеешь? Цитата Qraizer @ Ага, "костыль", который выглядит чище, а работает не хуже. Костыль - это стрельба из пушки по воробьям.Вот. Собственно это и есть тот критерий, который оправдано можно закостылить scope()ом... Цитата Qraizer @ Если скоуп внезапно захочет чего-то сложного, то внезапно убирается scope(...) и делается та самая RAII-обертка. Но на моей практике такого никогда не было. Если я принял решение использовать scope(...), то в будущем так и не возникала необходимость его менять на RAII.но вдруг и внезапно – скоуп может захотеть владеть разными ресурсами, в разном количестве и с разной стратегией владения. Это называется оверинжиниринг, когда код усложняется "на всякий случай", даже когда вероятность возниконовения этого "всякого случая" в будущем близка к нулю. Я сам страдаю таким и раньше мне приходилось местами заставлять себя писать scope(exit) вместо RAII-обертки. Потому что объективная оценка показывала, что в данном случае "вдруг и внезапно скоуп никогда не захочет владеть разными ресурсами, в разном количестве и с разной стратегией владения." Сейчас уже почти привык не городить абстракции и обобщения там, где они вероятно не понадобятся никогда. Цитата Qraizer @ А по твоему удобнее эти goto? Да и cleanup гораздо примитивнее scope(exit).Исполнение данных тобой инструкций – да, автоматическое. С этим и __attribute__((__cleanup__())) справляется. Интересно, почему его не включали в Стандарт C? Это же так удобно, по твоим словам. А так сишники народ странный, но думаю многим из них понравился бы scope(exit). А Стандарт это дело консервативное и тормозное. Сколько ждали появления в плюсах лямбд и auto? Добавлено Цитата korvin @ Да, вспомнил. Я пытался юзать Zig, но как-то не зашло. Слишком уж странные у них лозунги. ЕНМНИП, у них до сих пор нет лямбд. и ещё Zig, например |
Сообщ.
#412
,
|
|
|
Цитата applegame @ ЕНМНИП, у них до сих пор нет лямбд. Так это приукрашенный C, откуда там лямбды? =) |
Сообщ.
#413
,
|
|
|
Цитата korvin @ Они там полиморфизьм обсуждают Почему бы и лямбды не сделать? Они вроде не противоречит их девизам. Так это приукрашенный C, откуда там лямбды? =) |
Сообщ.
#414
,
|
|
|
Цитата applegame @ Этот PQClear встречается во всей моей обертке вокруг libpq ровно один раз, а именно в scope(exit) в одном из методов класса Connection. Это было не очевидно из твоего кода. Если так, то спорить тут не о чем. Цитата Тогда двай уж и scope(exit) вынесем в отдельную функцию Если мы это сделаем, то это будет уже другой подход. Понимаешь? Цитата И знаешь чем второе лучше первого? Я достаточно подробно описал твое "второе" в предыдущем ответе тебе. И даже сказал, что не вижу в этом подходе ничего плохого, просто RAII более универсальный подход. Цитата Нет бесполезного и странно выглядящего для людей не знающих C++ объявления переменной lock, которая нигде потом явно не используется. Зато есть странно выглядищий для людей не знакомым с паттерном вызов функции с передачей лямбды, хотя логично делать эти действия на том же уровне, поскольку контекст тот же и мы не специфицируем никакое поведение. Зависит от того, к чему привык конкретный программист, который будет читать код. Вкусовщина. Цитата Самый что ни на есть настоящий костыль. Я тебя уже просил привести свое определение термина "костыль". Никакой принципиальной разницы тут нет, поскольку и в случая RAII и в случае bracket pattern ты освободишь ресурс автоматически. В первом случае за счет "лишнего" объекта, во втором - за счет "лишних" вызова функции и лямбды. Цитата заверни scope(...) в отдельную функцию (получится тот же using/with/try-with-resources, только лучше, потому что гибче) или делай RAII. Если ты используешь scope(exit) просто в реализации bracket pattern, то для работы с ресурсом ты используешь bracket pattern, а не scope(exit), понимаешь? scope(exit) у тебя просто часть реализации, там вооще мог быть try...catch, это не имеет принципиального значения Впрочем, я писал уже, что scope(exit) лучше finally, хотя и не принципиально. Цитата Цитата D_KEY @ Это как сказать, что вездеход лучше автомобиля, потому что вездеход может быть точно также использован для езды по болотам. Но RAII выигрывает и у них. Хотя бы тем, что может быть точно так же использован для полей структуры/класса. У автомобиля есть преимущества перед вездеходом, у bracket pattern перед RAII можешь такие указать? Добавлено Цитата korvin @ Цитата applegame @ Не знаю что за defer (Go?) Да f, err := os.Open("some/file") if err != nil { return err } defer f.Close() Там, кстати, не собираются делать аналог try-with-resources? А with*-функции используют? |
Сообщ.
#415
,
|
|
|
Цитата D_KEY @ Я словами это говорил:И потом еще неоднократно повторял. Но ты походу писатель а не читатель Впрочем, я тебя понимаю, кому охота читать портянки бессодержательных споров с Килей. Это было не очевидно из твоего кода. Если так, то спорить тут не о чем. Цитата D_KEY @ Конечно. Но ты же сам придумал это сравнение? Изначально-то речь шла о ситуации, когда у тебя выбор самому писать одноразовую RAII-обертку или воспользоваться одноразовым же scope(exit). А тут ты приводишь пример готовой RAII-обертки из стандартной либы да и еще подразумевая многократное ее применение.Если мы это сделаем, то это будет уже другой подход. Понимаешь? Цитата D_KEY @ Лямбда подхватывает текущий контекст. Кроме того лямбда вообще может выглядеть просто как скоуп, который лочится. Например в D:Зато есть странно выглядищий для людей не знакомым с паттерном вызов функции с передачей лямбды, хотя логично делать эти действия на том же уровне, поскольку контекст тот же и мы не специфицируем никакое поведение. mutex.locked({ ... }); Цитата D_KEY @ Нет, сначала ты приведи свое определение термина "определение термина". Я тебя уже просил привести свое определение термина "костыль". Все субъективно, я привел свое мнение. А так вон фанаты сяшки или, прости господи, Zig будут называть любой твой RAII - вселенским злом и страшным костылем. И аргументы у них найдутся из серии: в этом вашем RAII-объекте непонятно что происходит, а в моей милой функции все явно написано. И хрен ты их переубедишь Я высказал свое мнение и написал, что именно считаю костылем. Тебе это не показалось костылем - ну и флаг тебе в руки, что еще ты от меня хочешь? Мы же тут просто мнениями обмениваемся и не ставим цели учить писать программы. Цитата D_KEY @ Да-да, так и есть. И scope(exit) очень удобно применять для реализации этого, хм паттерна, в языках, в которых существют исключения и ранний return.Если ты используешь scope(exit) просто в реализации bracket pattern, то для работы с ресурсом ты используешь bracket pattern, а не scope(exit), понимаешь? scope(exit) у тебя просто часть реализации, там вооще мог быть try...catch, это не имеет принципиального значения Впрочем, я писал уже, что scope(exit) лучше finally, хотя и не принципиально. До этого обсуждения ни разу не слышал, что это паттерн и что у него, оказывается, даже есть название. Хотя это похоже какой-то чисто хаскелевский мемасик. |
Сообщ.
#416
,
|
|
|
Сообщ.
#417
,
|
|
|
Цитата D_KEY @ Там, кстати, не собираются делать аналог try-with-resources? Нет, и не думаю, что станут: try-with-resources работает только в рамках вызова процедуры и одного потока (одной горутины) — слишком узкоспециализированный механизм. Кроме того, try-with-resources в Java работает только если класс реализует interface AutoCloseable { void close() throws Exception } а разные «ресурсы» могут иметь разные методы «захвата/освобождения» в соответствии с их семантикой: Open/Close, Lock/Unlock, Create/Delete и т.п. Либо заставлять всех использовать всегда один метод (Close, там или Release) — как-то тупо. Вводить в язык явное понятие ресурса с каким-нибудь спец-синтаксисом, типа помечать освобождающий метод каким-нибудь ключевым словом или спец-символом — ну хз. И это всё равно никак не поможет с разделяемыми ресурсами, например: package main import ( "fmt" "sync" "time" ) const nWorkers = 5 func main() { fmt.Println("ok1:") ok1() fmt.Println("\nok2:") ok2() fmt.Println("\nnot ok:") notOk() } func ok1() { var wg sync.WaitGroup wg.Add(nWorkers) // acquire for i := 0; i < nWorkers; i++ { go func(x int) { defer wg.Done() // release doSomeWork(x) }(i) } wg.Wait() } func ok2() { var wg sync.WaitGroup for i := 0; i < nWorkers; i++ { wg.Add(1) // acquire go func(x int) { defer wg.Done() // release doSomeWork(x) }(i) } wg.Wait() } func notOk() { var wg sync.WaitGroup for i := 0; i < nWorkers; i++ { go func(x int) { wg.Add(1) // acquire defer wg.Done() // release doSomeWork(x) }(i) } wg.Wait() } func doSomeWork(x int) { <-time.After(1 * time.Second) fmt.Println("done #", x) } => ok1: done # 2 done # 0 done # 4 done # 3 done # 1 ok2: done # 0 done # 2 done # 1 done # 3 done # 4 not ok: Program exited. try-with-resources тут никак не поможет, т.к. позволяет описать только вариант notOk. А в JDK, ЕМНИП, у HttpURLConnection освобождающий метод называется disconnect, а не close и соответствено класс не реализует AutoCloseable и использовать его в try-with-resources нельзя Цитата D_KEY @ А with*-функции используют? Ну, некоторые используют, но callback-style не всем нравится. |
Сообщ.
#418
,
|
|
|
Цитата applegame @ Если бы он все верно оценил, он бы так не написал. Очевидно, что он думал, что деструкторы объектов на куче вызываются по тем же правилам, что и деструкторы объектов на стеке. Это тебе очевидно и синтетического примера в 5 строчек. Если бы все было просто как ты пишешь, баги делали бы только студенты по своему не знанию. На практике у него может быть довольно не примитивный код, чтоб верно оценить все ньюансы. Именно по этому писать руками дополнительную строчку - может являтся источником ошибок. Ок, вот ты привел там функцию - с виду имитирующуюю RAII, в принципе такой вариант еще ладно, если знаешь что у тебя тут голый ресурс, и ты тут его же удаляешь - такое еще можно оправдать. Но ведь разные есть случаи, я понял бы если бы это была единная конструкция, хотя бы там через точку например. Но понимаешь ли, бывает так что пишешь new int, и тут же забываешь сделать delete, потому что это две конструкции, независимы друг от друга семантически. Так и тут. Цитата applegame @ Ну так они и пишут, в деструкторах оберток и кастомных делетерах unique_ptr. Это пишется в одной конструкции. Если было бы все так просто - все эти RAII нахер бы никому не упали. Какая проблема вызвать delete, после выделения ресурсов - да абсолютно никакой. И тем не менее в том же С++ утечек куча, из за того что люди полагаются на свои руки и память, а потом выхватывают утечки. Цитата applegame @ Нет в сяшке не тот же. Вызовуться только те scope(), которые успели отработать. Поведение scope(exit) в плане очистки ресурсов полностью совпадает с unique_ptr с кастомным деструктором. Похоже, ты не совсем понял оно работает. Вот посмотри очень короткий пример: https://run.dlang.io/is/7jJE7b Тут как бы и коню понятно что до второго scope оно не дойдет. Корректно ли отработает первый scope, если исключение произошло на этапе конструирования сложного объекта, вот в чем вопрос. Цитата applegame @ Я это понял так, что ты решил, что scope(exit) как-то влияет на это. Имелось ввиду, что ты можешь положится на scope, ну раз оно от RAII вообще никак не отличается по твоим словам, а гдето выше другой чувак понадеется на полноценный деструктор, и это приведет к ошибке, как в примере по ссылке. Цитата applegame @ Ну я не тащил сюда всякие странные багнутые куски кода. А так да, в C++ нет scope, но есть RAII, а в D есть и scope и RAII. Я его притащил - показать с какими проблемами можно столкнуться, полностью положившись на него. В С++ нет scope, потому что там нет GC, а в D есть GC, поэтому там и scope актуален. Для С++ этот scope(exit) - не более, чем синтаксический сахар. Цитата applegame @ Я не сразу понял. Когда я писал try/catch/finally я имел в виду совокупность всех возможных комбинаций и так же понял и твое try/catch/finally. Важно понимать, что scope(success)/scope(failure)/scope(exit) похожи на try/catch/finally, но отличия достаточно большие. По сути все отличия сводятся к удобству использования. Не надо просто писать все эти try/catch/finally, но например тотже try-with-resources/using - уже куда более удобны этих конструкций try/catch/finally, и вполне себе могут даже потягаться со scope(exit). Да и в такие языки любят тащить все попало, но scope(exit) - я там как то не встречал. Видимо даже там разрабы посчитали - что излишне вводить то, что уже есть в языке. |
Сообщ.
#419
,
|
|
|
Цитата Wound @ Такие ошибки и делают только студенты по своему незнанию.Если бы все было просто как ты пишешь, баги делали бы только студенты по своему не знанию. Цитата Wound @ Ну так scope(...) и надо применять только в таких случаях. Я же говорил много раз.Ок, вот ты привел там функцию - с виду имитирующуюю RAII, в принципе такой вариант еще ладно, если знаешь что у тебя тут голый ресурс, и ты тут его же удаляешь - такое еще можно оправдать. Цитата Wound @ Я хз как такое можно забыть. Ты же вот прямо только что выделил память, и если ты не страдаешь склерозом, в голове автоматом возникает мысль: "надо освободить ресурс", и ты тут же пишешь scope(exit). С таким же успехом ты можешь забыть написать кастомный делетер в unique_ptr. Вот если у тебя такое встречается много раз, то уже становится неудобно, но в таких случаях и unique_ptr с кастомным делетером становится неудобным.Но ведь разные есть случаи, я понял бы если бы это была единная конструкция, хотя бы там через точку например. Но понимаешь ли, бывает так что пишешь new int, и тут же забываешь сделать delete, потому что это две конструкции, независимы друг от друга семантически. Так и тут. Цитата Wound @ Конечно корректно, ведь конструирование происходит до scope(exit), соотвественно, если при конструировании произошло исключение, то scope(exit) не отработает. Разве это не очевидно?Тут как бы и коню понятно что до второго scope оно не дойдет. Корректно ли отработает первый scope, если исключение произошло на этапе конструирования сложного объекта, вот в чем вопрос. Цитата Wound @ Он положился на scope и scope сделал ровно то, что он и ожидал, не больше не меньше. Его "обманул" GC, а не scope.Имелось ввиду, что ты можешь положится на scope, ну раз оно от RAII вообще никак не отличается по твоим словам, а гдето выше другой чувак понадеется на полноценный деструктор, и это приведет к ошибке, как в примере по ссылке. Цитата Wound @ Наоборот, он столкнулся с проблемой, потому что не полностью положился на scope, а понадеялся на деструктор. Если бы он полностью положился на scope и написал бы в нем TTF_CloseFont() и TTF_Quit(), то все бы работало без сегфолтов.Я его притащил - показать с какими проблемами можно столкнуться, полностью положившись на него. Цитата Wound @ Неверно. scope(exit) и GC - вещи ортогональные. В моем же примере с PQClean, GC вообще никак не используется. И повторю еще раз: scope(...) может работать не только с ресурсами (в частности не только с памятью). И также повторю, что все RAII-парадигмы C++ работают и в D. Ну и какой это сахар, если для его реализации в плюсах надо маленькую либку написать, что и сделал Qraizer.В С++ нет scope, потому что там нет GC, а в D есть GC, поэтому там и scope актуален. Для С++ этот scope(exit) - не более, чем синтаксический сахар. Цитата Wound @ Это сущности чуть более высокого уровня, чем scope(exit), но их можно реализовать при помощи scope(exit).но например тотже try-with-resources/using Цитата Wound @ Разрабы тащат в языки все что им в голову взбредет, сам факт что разрабы что-то притащили или не притащили вообще не критерий. Тащат говно и наоборот хорошее не тащат сплошь и рядом. Да и в такие языки любят тащить все попало, но scope(exit) - я там как то не встречал. Видимо даже там разрабы посчитали - что излишне вводить то, что уже есть в языке. |
Сообщ.
#420
,
|
|
|
Цитата applegame @ Такие ошибки и делают только студенты по своему незнанию. Ну да, а остальные не делают никаких ошибок. Я уже где то такое слышал. Цитата applegame @ Ну так scope(...) и надо применять только в таких случаях. Я же говорил много раз. Ну вообще мы объясняли человеку почему лучше в его случае избавится от goto, и обернуть ресурс в RAII обертку, приводили разные примеры, пришол ты и сказал - как хорошо что в D такого говна нет, а есть scope(exit). А теперь ты говоришь - что не говорил что он весь такой из себя ахереть какой. Цитата applegame @ Я хз как такое можно забыть. Ты же вот прямо только что выделил память, и если ты не страдаешь склерозом, в голове автоматом возникает мысль: "надо освободить ресурс", и ты тут же пишешь scope(exit). С таким же успехом ты можешь забыть написать кастомный делетер в unique_ptr. Вот если у тебя такое встречается много раз, то уже становится неудобно, но в таких случаях и unique_ptr с кастомным делетером становится неудобным. Когда работаешь с сырым указателем - очень часто забываешь написать delete. Тут примерно тоже самое - потому что это отдельная конструкция. С кастомным делитером - сразу видно будет что ресурс не освобождается, просто по самой конструкции. А этот scope(exit) - не обязательно можно написать сразу после выделения, его можно написать и в конце и в середине кода, уже после выделения памяти под ресурс. А раз так написать можно - значит будь уверен кто нибудь непременно так и напишет. Весь вопрос - как долго будут потом багу искать. Может быть сразу найдут, а может кто то неделю в отладчике проведет. Я вот именно это имею ввиду. Да ты можешь написать - вызывай сразу после выделения памяти под ресурс, но от этого возможность написать его где угодно никуда не девается. Цитата applegame @ Конечно корректно, ведь конструирование происходит до scope(exit), соотвественно, если при конструировании произошло исключение, то scope(exit) не отработает. Разве это не очевидно? Ну например там: Цитата Установили соединение Открыли базу Начали получать доступ к таблице - исключение scope(exit){ Очистили ресурсы от таблицы Закрыли Базу Закрыли соединение } В итоге соединение и БД остались открытыми. Цитата applegame @ Он положился на scope и scope сделал ровно то, что он и ожидал, не больше не меньше. Его "обманул" GC, а не scope. Мы не знаем кто там кого обманул, вполне возможно что он написал все верно, а потом пришел вася, и вместо создания объекта на стеке как было, взял переделал создание объекта на куче. Еще раз повторяю - там синтетический пример, обычно такие пишут, чтоб не захламлять лишними деталями и не сбивать людей с толку. Вот допустим у меня проект, хренова туча классов/кода летит какая то ошибка, я не буду все это выкладывать на форум, чтоб спросить что не так. Я возьму напишу минимальный, синтетический пример для воспроизведения проблемы, и выкачу его на форум, там будет 2 класса и три строчки с выводом в консоль, а в реале, может быть сотни классов и строк кода. Цитата applegame @ Неверно. scope(exit) и GC - вещи ортогональные. В моем же примере с PQClean, GC вообще никак не используется. И повторю еще раз: scope(...) может работать не только с ресурсами (в частности не только с памятью). И также повторю, что все парадигмы C++, в том числе и RAII работают и в D. Ну и какой это сахар, если для его реализации в плюсах надо маленькую либку написать, что и сделал Qraizer. Ну да, scope ортогонален GC примерно на столько же, на сколько и finally. Для его реализации достаточно написать unique_ptr, можно и класс написать. Qraizer тебе писал аналог в D, чтоб оно и выглядело и юзалось прям как один в один, максимально приближенно. Т.е. по сути он тебе этот сахар и реализовал на плюсах. А так это ничем не отличается от любого класса, в деструкторе которого выполняется то, что у тебя выполняется в теле scope. Потому как оно ровно так же - гарантированно выполняется в конце блока, устойчиво к исключениям, по сути как и finally. Так что scope(exit) - в плюсах это синтаксический сахар, не более. Были бы лямбды в плюсах более лаконичными, хотя бы похожи на делегаты в шарпах, то можно было бы переписать код с std::unique_ptr с кастомным делитером примерно вот так: auto resource = std::unique_ptr(new CResource(), (e) => { //! free resource. delete e; }); По сути в плюсах все к этому и сводится, если убрать весь этот синтаксический шлак по уточнению типов и указанию шаблонных параметров всяких. Но на сколько я понимаю в плюсах такое написать нельзя из за скудного RTTI, поэтому и приходится чуть больше закорючек писать. Ну и по описанию: https://tour.dlang.org/tour/en/gems/scope-guards // scope guards allow placing allocations // and their clean up code next to each // other import core.stdc.stdlib : free, malloc; int* p = cast(int*) malloc(int.sizeof); scope(exit) free(p); Приводят ровно такой пример, который в С++ переписывается обычным unique_ptr, в примере free вызывается в scope(exit), в плюсах будет вызываться в кастомном делитере. Цитата applegame @ Разрабы тащат в языки все что им в голову взбредет, сам факт что разрабы что-то притащили или не притащили вообще не критерий. Тащат говно и наоборот хорошее не тащат сплошь и рядом. Ну в такие ЯП как JAVА/C# по моему тащат вообще все подряд, что можно затащить. |