Здравствуйте, ArtDenis, Вы писали:
AD>Ну вот прям щас сделал поиск в гитхабе, получил >7 тысяч new std::ifstream. Ткнул на случайный проект и вижу: AD>
AD>...
AD> auto src_file = new std::ifstream(path);
AD> if (!src_file->is_open())
AD> throw std::runtime_error("Unable to open source file " + path);
AD>...
AD>
AD>
Что любопытно, там вообще элементарно избежать подобных проблем. Вместо того, чтобы:
std::istream* source = &std::cin;
std::istream* target = nullptr;
std::ostream* output = &std::cout;
if (args.count("src")) {
auto path = args["src"].as<std::string>();
auto src_file = new std::ifstream(path);
if (!src_file->is_open())
throw std::runtime_error("Unable to open source file " + path);
source = src_file;
}
...
if (source != &std::cin)
delete source;
if (target)
delete target;
if (output != &std::cout)
delete output;
можно было бы, например, сделать так:
std::istream source_file; // Не открываем сразу.
std::istream* source = &std::cin;
std::istream target_file; // Не открываем сразу.
std::istream* target = nullptr;
std::ostream output_file; // Не открываем сразу.
std::ostream* output = &std::cout;
if (args.count("src")) {
auto path = args["src"].as<std::string>();
source_file.open(path);
if (source_file->is_open())
throw std::runtime_error("Unable to open source file " + path);
source = &source_file;
}
...
// Блок с ручным delete не нужен вообще.
AD>PS: ХЗ что за проект, но у него 1800 звёзд )
Такое ощущение, что C++ный код там писали Python-исты. Они, например, прямо в main бросают исключения не озадачившись заключить код в try..catch, как будто вылетевшее из main исключение кто-то обещал обязательно поймать и показать пользователю.
Да и вообще, наглядное свидетельство того, что как только появляется один характерный признак говнокода (слишком длинные функции), так следом обнаружатся и другие.
AD>PPS: справедливости ради надо сказать, что в некоторых найденных проектах народ делает сначала new std::ifstream, а затем присваивает результат во владеющий умный указатель
Справедливости ради нужно сказать, что я не утверждал "возьмите std::ifstream и файл будет обязательно закрыт". Дословно было сказано вот что: "Если вы открыли файл, то не закрыть его вы просто так уже не сможете." Т.е. не просто так не закрыть сможете, что Константин Б и продемонстрировал подсадив в код явный баг.
Но у него баг простой и очевидный. Можно было бы поизощреннее пример привести:
Его изобрели для одной задачи — пилить web browser, и для этой задачи оно как раз уникально подходит.
Браузерами пользуются много миллионов людей каждый день, они компилируют и запускают мегабайты чужого кода на каждый клик, а цена security bugs для них прям катастрофическая.
Например, если зловредный javascript или там css, прилетевший из какой-нибудь рекламы, сможет получить контроль над целым браузером и своровать данные из соседней закладки, в которой интернет банк — такой браузер мгновенно превратится в тыкву.
Для браузеров, безопасность кода — цель номер один.
Поэтому Rust такой. Плевать на usability, время компиляции, синтаксис из фильмов про пришельцев, время разработки, и сложности найма программистов.
Если все эти минусы чинят пару классов security bugs, именно для браузеров это всё равно хороший tradeoff.
Браузеры не уникальны, кроме них есть ещё kernel-mode куски операционных систем, гипервизоры, и возможно сервера баз данных.
Вот для такого, раст вполне норм.
Однако сторонники раста похоже верят, что это лучший в мире язык, и настойчиво предлагают переписывать на нём весь имеющейся в мире софт.
Это очень плохая идея, потому что подавляющее большинство кода, который пилят программисты, не имеет таких же требований к безопасности.
Например, почти весь user mode код уже неплохо изолирован от окружающего мира, потому что отдельный процесс, и в современных ОС ещё сверху песочницы, контейнеры, привилегии процессов, и подобное.
Скорость разработки часто имеет огромное значение для проектов.
Для кучи софта, языки вроде Java и C#, которые компилируются в байт код и автоматически управляют памятью, это очень хороший tradeoff. Они примерно такие же безопасные как тот раст, не сильно медленнее, жгут несколько больше памяти из-за GC, но память всё ещё экспоненциально дешевеет со временем.
Здравствуйте, T4r4sB, Вы писали:
AD>>Ну вот прям щас сделал поиск в гитхабе, получил >7 тысяч new std::ifstream. Ткнул на случайный проект и вижу:
TB>Мне кажется, это не очень вменяемые люди. Ну или просто не крестовики. Писали на жабошарпах всю жизнь.
А это не важно. Важно то, что пишут, не понимая всех тонкостей и даже азов. Язык позволяет, а компилятор не бъёт по рукам. Это данность и с этим ничего не поделаешь )
Здравствуйте, m2user, Вы писали:
M>Небрежные питонисты, т.к. аналогичный код является потенциально проблемным даже в языке с GC. M>Если будет исключение тут M>
M>то delete source не будет вызван. И пока GC не доберется до объекта, будет висеть открытый файловый дескриптор, препятствуя удалению файла например.
Их оправдывает то обстоятельство, что все это в main происходит: если исключение вылетит, то программа завершит свою работу и уже ОС подчистит за ней.
Подобный подход временами используют для "разовых утилит", т.к. для программ, которые запускаются, быстро что-то делают и завершают свою работу. В таких случаях даже память не освобождают в программе. Если не ошибаюсь, разработчики PVS-Studio про свой анализатор рассказывали, что они такой подход эксплуатируют: мол, на анализ файла стартует новый процесс, в этом процессе память не освобождается, т.к. при работе это не нужно (да и сложно анализ реализовывать, т.к. при освобождении памяти висячие ссылки и протухшие указатели могут появится), а после работы вся память будет освобождена после завершения процесса.
Правда, разработчики упомянутого CTranslate2/cli/translator.cc и здесь где-то на полпути остановились, зачем-то блок с delete написали. Явно не от большого опыта и хорошего понимания происходящего.
Здравствуйте, ArtDenis, Вы писали: AD>А это не важно. Важно то, что пишут, не понимая всех тонкостей и даже азов. Язык позволяет, а компилятор не бъёт по рукам. Это данность и с этим ничего не поделаешь )
Но всё же это — ненастоящие шотландцы!
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
AD>>А это не важно. Важно то, что пишут, не понимая всех тонкостей и даже азов. Язык позволяет, а компилятор не бъёт по рукам. Это данность и с этим ничего не поделаешь ) S>Но всё же это — ненастоящие шотландцы!
Может и настоящие, но необученные еще
Вообще, если посмотреть на человека, который в первый раз в жизни взялся за гвозди и молоток, то зрелище будет жалкое, да и без отбитых пальцев вряд ли обойдется. Виноват ли в этом молоток и настоящий ли шотландец за него взялся?
Ну а так-то шуруп, забитый молотком, держит лучше, чем гвоздь, закрученный отверткой. Что в обсуждаемом фрагменты мы и наблюдаем.
Здравствуйте, Sinclair, Вы писали:
S>Но всё же это — ненастоящие шотландцы!
Блин, я понимаю что эта аналогия тут сама напрашивается, но ведь и правда если крестовик без повода лепит new, то это невменько какоето а не крестовик.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, so5team, Вы писали:
S>Ну а так-то шуруп, забитый молотком, держит лучше, чем гвоздь, закрученный отверткой. Что в обсуждаемом фрагменты мы и наблюдаем.
Мы наблюдаем спор двух субъективностей.
Типа программисты на С++ инстинктивно знают, где надо писать с new, а где — без new.
А программисты на zig — инстинктов лишены, потому не знают, где ставить defer, а где — не ставить.
С таким подходом я предлагаю сразу вычеркнуть из "программистов zig" всех, кто не умеет правильно defer-ить. Ведь всех не понимающих тонкости времени жизни плюсовых объектов мы из С++-программистов вычеркнули, так что пуркуа бы и не па?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>>Ну а так-то шуруп, забитый молотком, держит лучше, чем гвоздь, закрученный отверткой. Что в обсуждаемом фрагменты мы и наблюдаем. S>Мы наблюдаем спор двух субъективностей. S>Типа программисты на С++ инстинктивно знают, где надо писать с new, а где — без new. S>А программисты на zig — инстинктов лишены, потому не знают, где ставить defer, а где — не ставить.
Нет, спор не об этом.
Вы серьезно считаете, что пример Константин Б с "new std::ifstream" в этом споре корректен?
Здравствуйте, Sinclair, Вы писали:
S>Типа программисты на С++ инстинктивно знают, где надо писать с new, а где — без new.
Дык все очень просто: не нужно писать new
С дефером сложнее
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, so5team, Вы писали: S>Нет, спор не об этом.
S>Вы серьезно считаете, что пример Константин Б с "new std::ifstream" в этом споре корректен?
Он станет некорректен сразу после того, как компилятор надаёт ему за такое по рукам.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>>Вы серьезно считаете, что пример Константин Б с "new std::ifstream" в этом споре корректен? S>Он станет некорректен сразу после того, как компилятор надаёт ему за такое по рукам.
Лучше ли одно действие чем два?
Если нам нужно выполнить два действия вместо одного, то можно ли забыть второе?
Можно ли между первым и вторым действиями со временем вставить что-то, что приведет к преждевременному return-у?
Вот это все и подразумевалось, когда задавался вопрос "Круто тем, что его можно забыть написать?"
И это мы не затрагиваем такой момент как включение объекта файл в какой-то агрегат (структуру, массив, хэш-таблицу) с последующим копированием-перемещением экземпляра этого агрегата.
В качестве контраргумента приводится код, который заведомо некорректен:
auto * file = new std::ifstream{path};
... // Подразумевается, что delete не будет.
Можно ли написать такой некорректный код в C++? Да. С этим никто и не спорил.
Имеет ли смысл рассматривать то, что делает (или чего не делает) заведомо некорректный код?
Как по мне, так ни в коем случае.
Можно ли рассуждать о том, насколько сложно написать корректный код на C++?
Вполне. И, что характерно, написать корректный код не сложно. Самый простой вариант уже был показан.
Но даже если хочется именно C++ (ну у человека Java в ДНК, мозга нет в принципе), ну бывает, достаточно на вас посмотреть и почитать что вы здесь пишете. Ну OK, специально для вас:
auto file = std::make_unique<std::ifstream>(path);
Все. Остальное за нас сделает компилятор.
И опять же, нет надобности ни в каких defer.
Ну и еще одно: пример с new std::ifstream{path} -- это вообще не про отсутствие автоматического закрытия файла (которое типа было обещано). Это вообще про другой тип ошибки. Устраните эту ошибку и вы получите те самые гарантии, которые якобы не выполняются. При этом, устранив ошибку, вам не придется делать ничего дополнительного чтобы закрыть файл.
Здравствуйте, so5team, Вы писали:
S>Здравствуйте, Sinclair, Вы писали:
S>>>Вы сейчас тупите или стебетесь? S>>Я абсолютно серьёзен.
S>Ну тогда давайте серьезно. Для того, чтобы написать корректный код на zig программисту нужно сделать два действия: S>
Здравствуйте, Разраб, Вы писали:
Р>В зиге вы делаете все явно(это описано в манифесте), в плюсах получается некоторая магия которую вы не контролируете.
Недавно узнал, что для некоторых программистов неявное появление this в нестатических методах класса -- это уже магия. Так что, да, неконтролируемая магия
Здравствуйте, so5team, Вы писали:
S>Недавно узнал, что для некоторых программистов неявное появление this в нестатических методах класса -- это уже магия. Так что, да, неконтролируемая магия