LINUX.ORG.RU

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

 


1

2

Привет, ЛОР.

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

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

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

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

★★★★★

Как подсказывает инет, можно попробовать включить исключения, и смотреть в 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 ★★★★★
()
Ответ на: комментарий от 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 ★★★
()
Ответ на: комментарий от firkax

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

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

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

hateyoufeel ★★★★★
()

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 ★★★★★
()
Ответ на: комментарий от dataman

Не думаю. :)

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

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

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

fsb4000 ★★★★★
()
Ответ на: комментарий от 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 ★★★★★
() автор топика
Ответ на: комментарий от anonymous

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

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

kvpfs_2
()
Ответ на: комментарий от 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

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

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

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

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

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

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

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

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

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

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

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

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

kvpfs_2
()