Friday, December 27, 2024

Predefined System error enumerations

Overview
The standard library provides predefined enumeration classes to define error conditions for these categories: generic_category, iostream_category and future_categoty.

Details
The following discusses  some of the predefined error conditions and error codes. They are organized into a enum class for each category. 
In addition, helper classes is_error_condition_enum  or is_error_condition_enum are defined to indicate if they are defined for a error_code or error_condition
The enumerated value is used by helper functions  make_error_code() and make_error_condition() to create a error_code or a error_condtion.

is_error_code_enum
This is a traits class to identify whether a particular type is an error code enum type, and thus can be used to construct or assign values to objects of type error_code.
Syntax
template <class T>
struct is_error_code_enum : public false_type {};
The standard header only provides the default definition, which simply inherits from false_type. But it should be specialized as inheriting from true_type to enable the construction of error_code object from error code enum types. The standard error condition types  io_errc and future_errc inherit true_type.

is_error_condition_enum
This is a traits class to identify whether a particular type is an error condition enum type, and thus can be used to construct or assign values to objects of type error_condition.
Syntax
template <class T>
struct is_error_condition_enum : public false_type {};
The standard header only provides the default definition, which simply inherits from false_type. But it should be specialized as inheriting from true_type to enable the construction of error_condition object from error condition enum types. The standard error condition type errc inherit true_type.

make_error_code()
Syntax
make_error_code(econd_enum e)

Creates an error_code for econd_enum e and returns it.
It's equivalent to error_code(static_cast<int>(e), cat) where cat is the category for which econd_enumaration enum is defined.

make_error_condition()
Syntax
make_error_condition(econd_enum e)

Creates an error_condition for econd_enumaration enum e and returns it.
It's equivalent to error_condition(static_cast<int>(e), cat) where cat is the category for which econd_enumaration enum is defined.
used to construct or assign values to objects of type error_code.

errc
enum class with enumerators for the error_conditions with one to one mapping to error codes from POSIX error codes which are found in <cerrno> header file. 
Type trait class is_error_condition_enum is implemented returning  true, indicating that it's an error_condition enumeration. 
Helper functions make_error_code() and make_error_condition() are also implemented.
error_condition ecnd = make_error_condition(errc::invalid_argument);
//same as
//error_condition ecnd = make_error_condition(EINVAL,  std::generic_category());
The complete list can be viewed here. 

void print_error(const std::string& details, std::error_code error_code)
{
    std::string value_name;
    if (error_code == std::errc::invalid_argument)
        value_name = "std::errc::invalid_argument";
    if (error_code == std::errc::no_such_file_or_directory)
        value_name = "std::errc::no_such_file_or_directory";
    if (error_code == std::errc::is_a_directory)
        value_name = "std::errc::is_a_directory";
    if (error_code == std::errc::permission_denied)
        value_name = "std::errc::permission_denied";
 
    std::cerr << details << ":\n  "
              << std::quoted(error_code.message())
              << " (" << value_name << ")\n\n";
}
 
void print_errno(const std::string& details, int errno_value = errno)
{
    print_error(details, std::make_error_code(std::errc(errno_value)));
}
 
int main()
{
    /*prints
    Detaching a not-a-thread...
    Error detaching empty thread:
        "Invalid argument" (std::errc::invalid_argument)
    */
    std::cout << "Detaching a not-a-thread...\n";
    try
    {
        std::thread().detach();
    }
    catch (const std::system_error& e)
    {
        print_error("Error detaching empty thread", e.code());
    }
 
    /*prints
    Opening nonexistent file...
    Error opening nonexistent file for reading:
        "No such file or directory" (std::errc::no_such_file_or_directory)
    */
    std::cout << "Opening nonexistent file...\n";
    std::ifstream nofile{"nonexistent-file"};
    if (!nofile.is_open())
        print_errno("Error opening nonexistent file for reading");
 
    /*prints
    Reading from directory as a file...
    Error reading data from directory:
        "Is a directory" (std::errc::is_a_directory)    
    */
    std::cout << "Reading from directory as a file...\n";
    std::filesystem::create_directory("dir");
    std::ifstream dir_stream{"dir"};
    [[maybe_unused]] char c = dir_stream.get();
    if (!dir_stream.good())
        print_errno("Error reading data from directory");
 
    /*prints
    Open read-only file for writing...
    Error opening read-only file for writing:
        "Permission denied" (std::errc::permission_denied)    
    */
    std::cout << "Open read-only file for writing...\n";
    std::fstream{"readonly-file", std::ios::out};
    std::filesystem::permissions("readonly-file", std::filesystem::perms::owner_read);
    std::fstream write_readonly("readonly-file", std::ios::out);
    if (!write_readonly.is_open())
        print_errno("Error opening read-only file for writing");

future_errc
enum class with enumerators for error_codes  for future errors. 
Type trait class  is_error_code_enum is implemented  returning  true,  indicating that it's an error_code enumeration. 
Helper functions make_error_code() and make_error_condition() are also implemented.
error_condition ecnd = make_error_condition(future_errc::future_already_retrieved);
//same as
//error_condition ecnd = make_error_condition(1,  std::future_category());
The complete list can be viewed here.

    std::promise<int> prom;
    //prints:[future already retrieved]
    try 
    {
        prom.get_future();
        prom.get_future();   // throws std::future_error with future_already_retrieved
    }
    catch (std::future_error& e) 
    {
        if (e.code() == std::make_error_condition(std::future_errc::future_already_retrieved))
            std::cerr << "[future already retrieved]\n";
        else 
            std::cerr << "[unknown exception]\n";
    }

io_errc
enum class with enumerators for io stream errors. 
Type trait class  is_error_code_enum is implemented  returning  true, indicating that it's an error_code enumeration. 
Helper functions make_error_code() and make_error_condition() are also implemented.
error_condition ecnd = make_error_condition(io_errc::stream);
//same as
//error_condition ecnd = make_error_condition(1,  std::iostream_category());
The complete list can be viewed here.
    //prints:failure caught: stream error condition
    try 
    {
        std::cin.rdbuf(nullptr);    // throws
        std::cin.exceptions (std::ios::failbit|std::ios::badbit);
    } 
    catch (std::ios::failure& e) 
    {
        std::cerr << "failure caught: ";
        if ( e.code() == std::make_error_condition(std::io_errc::stream) )
            std::cerr << "stream error condition\n"; 
        else
            std::cerr << "some other error condition\n";
    }


No comments:

Post a Comment