LINUX.ORG.RU

Как подробно диагностировать ошибки std::fstream

 


1

2

Привет, ЛОР.

Вот такой вот нубовопрос нарисовался по языку, на котором я пишу больше 10 лет…

В С++ после fstream::open() я могу вызвать is_open(), который и сообщит мне, удалось ли открыть файл. А вот как в случае неудачи получить более полную диагностику?

Что встречал: рекомендацию зачитывать глобальный errno и по желанию вызывать strerror().

Правильно ли это? errno ведь вообще из Си пришёл…

★★★★★

Дык все эти fstream емнип просто обвязка вокруг старого доброго сишного open.

AntonI ★★★★★
()

Как подсказывает инет, можно попробовать включить исключения, и смотреть в e.what(). Но там может быть такое же непонятно что, без конкретной проблемы.

Правильно ли это? errno ведь вообще из Си пришёл…

Ну и что? Совместимость с сями - один из столпов C++, и никуда не денется.

seiken ★★★★★
()

В С++ послеfstream::open()я могу вызватьis_open(), который и сообщит мне, удалось ли открыть файл. А вот как в случае неудачи получить более полную диагностику?

Судя по всему, никак. Только ловить эксепшон и печатать в консоль .what().

https://en.cppreference.com/w/cpp/io/basic_ios/exceptions

hateyoufeel ★★★★★
()
Ответ на: комментарий от seiken

Ну и что? Совместимость с сями - один из столпов C++, и никуда не денется.

Как минимум, errno – не часть стандарта C. Это юниксовая штука, которой в той же венде нету.

hateyoufeel ★★★★★
()
Ответ на: комментарий от hateyoufeel

Как минимум, errno – не часть стандарта C. Это юниксовая штука, которой в той же венде нету.

Это был ответ на «пришёл из С», как будто С - это что-то плохое.

seiken ★★★★★
()

Стримы в stl проектировали какие-то чушпаны. Так что лучше возьми другую библиотеку. Это сразу снимет все будущие проблемы.

ox55ff ★★★★★
()
Ответ на: комментарий от hateyoufeel

Как минимум, errno – не часть стандарта C. Это юниксовая штука, которой в той же венде нету.

В C++ errno есть: https://en.cppreference.com/w/cpp/error/errno

И на винде посредством VC++ вот такое вполне себе компилируется:

#include <iostream>
#include <cerrno>

int main()
{
    std::cout << errno << std::endl;
}

Другое дело, что будет ли это errno на Windows какое-то осмысленное значение иметь…

eao197 ★★★★★
()

В плюсах всё завязано на ловле try catch исключений, идиотская система, учитывая то, что из-за них работа с thread'ами превращается в головную боль (система для ловли ошибок порождающая ещё больше ошибок...). Лучше как уже сказали взять другую либу и не парить себе мозги.

Dr64h ★★★★
()

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

snizovtsev ★★★★★
()
Ответ на: комментарий от firkax

Какого из стандартов оно не часть? Только проверь перед ответом.

Да, ок. Ты прав. errno есть в сишном стандарте. Но кодов ошибок там почти нет, кроме EDOM, EILSEQ и ERANGE. Так что всё равно использование errno для I/O не будет переносимым.

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

hateyoufeel ★★★★★
()
Ответ на: комментарий от Dr64h

из-за них работа с thread’ами превращается в головную боль

Можешь привести пример? Я что-то такого не встречал.

rupert ★★★★★
()

https://en.cppreference.com/w/cpp/io/basic_ios/fail

#include <cstdlib>
#include <fstream>
#include <iostream>
 
int main()
{
    std::ifstream file("test.txt");
    if (!file) // operator! is used here
    {  
        std::cout << "File opening failed\n";
        return EXIT_FAILURE;
    }
 
    // typical C++ I/O loop uses the return value of the I/O function
    // as the loop controlling condition, operator bool() is used here
    for (int n; file >> n;)
       std::cout << n << ' ';
    std::cout << '\n';
 
    if (file.bad())
        std::cout << "I/O error while reading\n";
    else if (file.eof())
        std::cout << "End of file reached successfully\n";
    else if (file.fail())
        std::cout << "Non-integer data encountered\n";
}
fsb4000 ★★★★★
()
Ответ на: комментарий от MOPKOBKA

Какую?

https://github.com/cppfastio/fast_io

fast_io is a C++20 input/output library that provides exceptional speed and is designed to replace the commonly used and libraries. It is a header-only library and is licensed under the MIT license, making it easy to include in any project. However, it requires a C++20 compiler that supports concepts.

Я помню агрессивные наезды авторши на fmtlib. :)

dataman ★★★★★
()
Ответ на: комментарий от eao197

Не только VC++. У меня оно собралось под винду со стареньким MinGW и на тестовом заблокированном файле после пропускания через strerror() выдало Permission denied. Так что я ещё почитаю мнения и отмечу тему решённой, пожалуй…

hobbit ★★★★★
() автор топика
Ответ на: комментарий от Dr64h

C++ exceptions are becoming more and more problematic

Эта шутка такая? Товарищ шлёт по пол миллиона исключений в секунду в каждом потоке (а их 12) и говорит: «ц-ц-ц, караул, хеллоу ворлд тормозит!». Товарища надо тыкнуть в букварь:

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

Исключение, это когда раз в квартал, когда небо на землю. В остальных случаях - коды возврата, optional, etc.

Не, ну правда, х-ня какая-то, так можно что угодно в 100500 потоков потестить - запрос ресурсов у ОС, IO, картина будет той же.

kvpfs_2
()
Ответ на: комментарий от Dr64h

Exceptional Threads

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

C++ exceptions are becoming more and more problematic

А тут интересные результаты. Как, например:

Single threaded the fib code using std::expected is more than four times slower than using traditional exceptions. Of course the overhead is less when the function itself is more expensive, as in the sqrt scenario. Nevertheless the overhead is so high that std::expected is not a good general purpose replacement for traditional exceptions.

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

rupert ★★★★★
()
Ответ на: комментарий от LongLiveUbuntu

" Дружок, я все знаю, я сам, брат, из этих" (c) ДДТ.

Но в данном случае надо полирнуть библиотеку, которая не должна зависеть от Qt.

hobbit ★★★★★
() автор топика
Ответ на: комментарий от dataman

Не думаю. :)

и как ты определил? по аватарке? тут у половины лора женские аватарки.

Вот одно из его видео, можешь по голосу определить: https://youtu.be/CefgZlXeMUg

А так можешь в Discord ему написать. Это китаец который живёт в США.

fsb4000 ★★★★★
()
Ответ на: комментарий от hobbit

Но в данном случае надо полирнуть библиотеку, которая не должна зависеть от Qt.

А ты сделай ещё так, чтобы она и от STL не зависела.

EXL ★★★★★
()
Ответ на: комментарий от hobbit

Вы уверены что до конца понимаете зачем вам плюсовые стримы? К С-шным файлам это мало отношения имеет, на самом деле.

bugfixer ★★★★★
()
Ответ на: комментарий от EXL

А ты сделай ещё так, чтобы она и от STL не зависела.

И вместо std::string использовать char*? Она уже сейчас не слишком простая, а тогда станет просто неподдерживаемой. Это не ядро ОС и не что-то реалтаймовое. Это прикладная библиотека, она много работает со строками и чуть-чуть с файлами.

Ну да, в этом случае можно пойти в обратном направлении и затащить туда QtCore. Многие проблемы, кстати, исчезнут. Но как-то жалко, предыдущий автор заботливо делал её так, чтобы кроме STL, других зависимостей не было.

hobbit ★★★★★
() автор топика
Последнее исправление: hobbit (всего исправлений: 2)

В C++ есть свой strerror():

#include <cerrno>
#include <iostream>
#include <string>
#include <system_error>

int main() {
    std::error_condition econd = std::generic_category().default_error_condition(EBADF);
    std::cout << "Category: " << econd.category().name() << '\n'
              << "Value: " << econd.value() << '\n'
              << "Message: " << econd.message() << '\n';

    return 0;
}

$ ./a.out 
Category: generic
Value: 9
Message: Bad file descriptor
Reset ★★★★★
()
Ответ на: комментарий от Reset

Спасибо. Правда, у нас тут среди поддерживаемых платформ есть колдунское чернокнижное легаси, где даже 11 не поддерживается. Но на будущее учту, не до конца времён же его нам поддерживать…

hobbit ★★★★★
() автор топика
Ответ на: комментарий от hateyoufeel

Ложь, клевета и провокация, т.е. 4.2.

В ANSI C есть errno, стандарт POSIX его сильно расширяет, но базовые возможности закрепляет стандарт ANSI C.

zx_gamer ★★★
()
Ответ на: комментарий от Dr64h

Вспомните про goto fail, взгрустните и поймите, что исключения гораздо удобнее.

zx_gamer ★★★
()
Ответ на: комментарий от hobbit

Ну могу предложить страшное зло, которое всё же чуть лучше STL: boost::asio

zx_gamer ★★★
()
Ответ на: комментарий от anonymous

Что за альтернатива? И главное - а зачем им вообще искать альтернативу? В умелых руках это вполне полезный инструмент. Я не говорю, что условная либа Х должна кидать исключения наружу, скорее это уместно внутри законченной единицы/модуля, это её ливер. Никакой епли с протаскиванием критических ошибок через стек вызовов.

А если у кого-то чего-то тормозит, то он сам виноват. Даже по той доке видно, что увеличение количества исключение в однопоточном режиме не приводит к серьёзному замедлению, и это считай что при пустом цикле без какой-то адекватной нагрузки. А это значит, что исключения весьма шустро работают.

kvpfs_2
()
Ответ на: комментарий от fsb4000

Да, уж.

Если на клетке слона прочтёшь надпись «буйвол», не верь глазам своим. ©️

dataman ★★★★★
()
Ответ на: комментарий от dataman

fmtlib

Кстати, интересный проект для C++20: https://github.com/Viatorus/emio

a safe and fast high-level and low-level character input/output library for bare-metal and RTOS based embedded systems with a very small binary footprint.

// High-level
std::string str = emio::format("The answer is {}.", 42);  // Format argument.

int answer{};
emio::result<void> scan_res = emio::scan(str, "The answer is {}.", answer);  // Scan input string.
if (scan_res) {
    emio::print("The answer is {}.", answer);  // Output to console.
}

// Without using heap.
emio::static_buffer<128> buf{};
emio::format_to(buf, "The answer is {:#x}.", 42).value();
buf.view();  // <- The answer is 0x2a.

// Low-level
emio::writer wrt{buf};
wrt.write_str(" In decimal: ").value();
wrt.write_int(42).value();
wrt.write_char('.').value();
buf.view();  // <- The answer is 0x2a. In decimal: 42.

emio::reader rdr{"17c"};
EMIO_TRY(uint32_t number, rdr.parse_int<uint32_t>());  // <- 17
EMIO_TRY(char suffix, rdr.read_char());                // <- c

В перспективе – конкурент fmtlib.


Добавил в https://github.com/p-ranav/awesome-hpp.

dataman ★★★★★
()
Ответ на: комментарий от kvpfs_2

Ок, критику в целом понял, принял.

Интересен такой вопрос, что там по раздуванию кода? Нашёл такую статью - Top 15 C++ Exception handling mistakes and how to avoid them, как раз про заблуждения на счёт исключений, так вот, там указано, что код может раздуваться в пределах 5 - 10%, 5 - 15%, а например здесь - Qt Exception Safety указано уже о 20%+. Есть ли какие-то более подробные сведения на этот счёт?

Dr64h ★★★★
()
Ответ на: комментарий от Dr64h

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

kvpfs_2
()
Ответ на: комментарий от Dr64h

Кстати, если говорить о реальных проблемах исключений, то это не скорость там или раздувание кода, а нахождение объектов в некорректном состоянии, исключение возникло, операцию закончили не до конца, на выходе кусок поврежденного дерьма. Возникает логичная мысль, что исключения ловить не надо, пусть приложение падает и сбрасывает корку, а нафиг тогда они вообще нужны, если это тот же abort(), но сильно переусложненный? Резонный вывод, если у тебя хеллоу ворлд в сотню строк. Если же приложение по сложности выше некоторого порога, состоит из отдельных, условно самостоятельных модулей, то вместо уронить софтину целиком, можно элегантно уронить лишь один модуль, сделать запись в журнал и перезапустить (возможно), при этом исключение в ядре софтины будет всё равно ронять в корку.

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

В общем это инструмент для более сложных задач, а не для хеллоу ворлдов.

kvpfs_2
()
Ответ на: комментарий от kvpfs_2

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

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

Возникает логичная мысль, что исключения ловить не надо, пусть приложение падает и сбрасывает корку, а нафиг тогда они вообще нужны, если это тот же abort()

Я в основном не заморачиваюсь и использую assert'ы с форматированным выводом.

Dr64h ★★★★
()
Ответ на: комментарий от Dr64h

Я в основном не заморачиваюсь и использую assert’ы с форматированным выводом.

Норм вариант.

Я чет сегодня полез std::stacktrace ковырять, вспомнился разговор здесь про исключения. Сырой стектрейс, вроде ГЦЦ14 должен начать что-то адекватное генерить.

kvpfs_2
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.