Wednesday, April 14, 2010

System error support in C++0x - part 5

[ part 1, part 2, part 3, part 4 ]

Creating your own error conditions

User-extensibility in the <system_error> facility is not limited to error codes: error_condition permits the same customisation.

Why create custom error conditions?

To answer this question, let's revisit the distinction between error_code and error_condition:

  • class error_code - represents a specific error value returned by an operation (such as a system call).
  • class error_condition - something that you want to test for and, potentially, react to in your code.

This suggests some use cases for custom error conditions:

  • Abstraction of OS-specific errors.

    Let's say you're writing a portable wrapper around getaddrinfo(). Two interesting error conditions are the tentative "the name does not resolve at this time, try again later", and the authoritative "the name does not resolve". The getaddrinfo() function reports these errors as follows:

    • On POSIX platforms, the errors are EAI_AGAIN and EAI_NONAME, respectively. The error values are in a distinct "namespace" to errno values. This means you will have to implement a new error_category to capture the errors.
    • On Windows, the errors are WSAEAI_AGAIN and WSAEAI_NONAME. Although the names are similar to the POSIX errors, they share the GetLastError "namespace". Consequently, you may want to reuse std::system_category() to capture and represent getaddrinfo() errors on this platform.

    To avoid discarding information, you want to preserve the original OS-specific error code while providing two error conditions (called name_not_found_try_again and name_not_found, say) that API users can test against.

  • Giving context-specific meaning to generic error codes.

    Most POSIX system calls use errno to report errors. Rather than define new errors for each function, the same errors are reused and you may have to look at the corresponding man page to determine the meaning. If you implement your own abstractions on top of these system calls, this context is lost to the user.

    For example, say you want to implement a simple database where each entry is stored in a separate flat file. When you try to read an entry, the database calls open() to access the file. This function sets errno to ENOENT if the file does not exist.

    As the database's storage mechanism is abstracted from the user, it could be surprising to ask them to test for no_such_file_or_directory. Instead, you can create your own context-specific error condition, no_such_entry, which is equivalent to ENOENT.

  • Testing for a set of related errors.

    As your codebase grows, you might find the same set of errors are checked again and again. Perhaps you need to respond to low system resources:

    • not_enough_memory
    • resource_unavailable_try_again
    • too_many_files_open
    • too_many_files_open_in_system
    • ...

    in several places, but the subsequent action differs at each point of use. This shows that there is a more general condition, "the system resources are low", that you want to test for and react to in your code.

    A custom error condition, low_system_resources, can be defined so that its equivalence is based on a combination of other error conditions. This allows you to write each test as:

    if (ec == low_system_resources)
    ...

    and so eliminate the repetition of individual tests.

The definition of custom error conditions is similar to the method for error_codes, as you will see in the steps below.

Step 1: define the error values

You need to create an enum for the error values, similar to std::errc:

enum class api_error
{
low_system_resources = 1,
...
name_not_found,
...
no_such_entry
};

The actual values you use are not important, but you must ensure that they are distinct and non-zero.

Step 2: define an error_category class

An error_condition object consists of both an error value and a category. To create a new category, you must derive a class from error_category:

class api_category_impl
: public std::error_category
{
public:
virtual const char* name() const;
virtual std::string message(int ev) const;
virtual bool equivalent(
const std::error_code& code,
int condition) const;
};

Step 3: give the category a human-readable name

The error_category::name() virtual function must return a string identifying the category:

const char* api_category_impl::name() const
{
return "api";
}

Step 4: convert error conditions to strings

The error_category::message() function converts an error value into a string that describes the error:

std::string api_category_impl::message(int ev) const
{
switch (ev)
{
case api_error::low_system_resources:
return "Low system resources";
...
}
}

However, depending on your use case, it may be unlikely that you'll ever call error_condition::message(). In that case, you can take a shortcut and simply write:

std::string api_category_impl::message(int ev) const
{
return "api error";
}

Step 5: implement error equivalence

The error_category::equivalent() virtual function is used to define equivalence between error codes and conditions. In fact, there are two overloads of the error_category::equivalent() function. The first:

virtual bool equivalent(int code,
const error_condition& condition) const;

is used to establish equivalence between error_codes in the current category with arbitrary error_conditions. The second overload:

virtual bool equivalent(
const error_code& code,
int condition) const;

defines equivalence between error_conditions in the current category with error_codes from any category. Since you are creating custom error conditions, it is the second overload that you must override.

Defining equivalence is simple: return true if you want an error_code to be equivalent to your condition, otherwise return false.

If your intent is to abstract OS-specific errors, you might implement error_category::equivalent() like this:

bool api_category_impl::equivalent(
const std::error_code& code,
int condition) const
{
switch (condition)
{
...
case api_error::name_not_found:
#if defined(_WIN32)
return code == std::error_code(
WSAEAI_NONAME, system_category());
#else
return code = std::error_code(
EAI_NONAME, getaddrinfo_category());
#endif
...
default:
return false;
}
}

(Obviously getaddrinfo_category() needs to be defined somewhere too.)

The tests can be as complex as you like, and can even reuse other error_condition constants. You may want to do this if you're creating a context-specific error condition, or testing for a set of related errors:

bool api_category_impl::equivalent(
const std::error_code& code,
int condition) const
{
switch (condition)
{
case api_error::low_system_resources:
return code == std::errc::not_enough_memory
|| code == std::errc::resource_unavailable_try_again
|| code == std::errc::too_many_files_open
|| code == std::errc::too_many_files_open_in_system;
...
case api_error::no_such_entry:
return code == std::errc::no_such_file_or_directory;
default:
return false;
}
}

Step 6: uniquely identify the category

You should provide a function to return a reference to a category object:

const std::error_category& api_category();

such that it always returns a reference to the same object. As with custom error codes, you can use a global:

api_category_impl api_category_instance;

const std::error_category& api_category()
{
return api_category_instance;
}

or you can make use of C++0x's thread-safe static variables:

const std::error_category& api_category()
{
static api_category_impl instance;
return instance;
}

Step 7: construct an error_condition from the enum

The <system_error> implementation requires a function called make_error_condition() to associate an error value with a category:

std::error_condition make_error_condition(api_error e)
{
return std::error_condition(
static_cast<int>(e),
api_category());
}

For completeness, you should also provide the equivalent function for construction of an error_code. I'll leave that as an exercise for the reader.

Step 8: register for implicit conversion to error_condition

Finally, for the api_error enumerators to be usable as error_condition constants, enable the conversion constructor using the is_error_condition_enum type trait:

namespace std
{
template <>
struct is_error_condition_enum<api_error>
: public true_type {};
}

Using the error conditions

The api_error enumerators can now be used as error_condition constants, just as you may use those defined in std::errc:

std::error_code ec;
load_resource("http://some/url", ec);
if (ec == api_error::low_system_resources)
...

As I've said several times before, the original error code is retained and no information is lost. It doesn't matter whether that error code came from the operating system or from an HTTP library with its own error category. Your custom error conditions can work equally well with either.

Next, in what will probably be the final instalment, I'll discuss how to design APIs that use the <system_error> facility.

427 comments:

«Oldest   ‹Older   401 – 427 of 427
resume for career change said...

In my own experience, I once worked on a cross-platform networking library where I had to handle different error codes for name resolution. The approach of defining distinct error conditions like "name_not_found_try_again" and "name_not_found" would have made my code much more readable and maintainable. I appreciate the step-by-step guide provided by the author, especially the implementation details of error_category and the use of error_condition. This blog post has definitely expanded my understanding of handling errors in C++ and will greatly influence my future coding practices.

English Speaking Video | Tips For English Speaking | Know more about English Speaking and English Learning from our English Speaking Course, Delhi (https://wabstalk.com/courses/) | Learn How To Improv said...

English Speaking Video | Tips For English Speaking | Know more about English Speaking and English Learning from our English Speaking Course, Delhi (https://wabstalk.com/courses/) | Learn How To Improve English | Class For Spoken English.
Awarded the Best English Speaking Institute In Delhi. Enroll yourself in our English Speaking Course, Delhi today and Improve your English Speaking skills. We offer different levels of English Speaking courses which will help you learn more about English Speaking. Introvert
Our English Speaking Course, Delhi will provide you with the insights of Soft Skills, Communication Skills, Interview Training, Personality Development and Spoken English Skills.
Reinvent Yourself with our Soft Skill training Courses which brings out the leadership qualities in you by boosting your confidence level, crafting your Communication Skills and developing your English Speaking Skills; transforming you into a Charismatic Personality.
Join the most trusted and authentic English Speaking Institute with flexible and customizable Personality Development and English Speaking Courses, Delhi.

Wabstalk.com

Ayush said...

Discover the latest trends in saree fashion at 5Elements. From contemporary designer sarees to traditional silk drapes, our collection showcases the most sought-after styles. Embrace the fusion of modern and ethnic designs, intricate embellishments, and vibrant hues. Stay ahead in the fashion game with our trendsetting sarees for every occasion.Buy Designer Women Sarees

Digital Pixal said...

Boost Your Online Presence with Top-notch An Digital Marketing Services in Delhi NCR . Our company offers SEO, SEM, Google ads, Facebook ads, Content Writing and more. Get the best services in the market with us. Are you looking for the top Digital marketing services in Delhi NCR to boost your online presence and drive business growth? Look no further! Digital Pixal is here to help you achieve your digital marketing goals with our exceptional services and expertise. Let's dive into some commonly asked questions related to digital marketing and why Digital Pixal is the best choice for your business.

MNK said...

Thanks for the great sharing!

BroadMind - IELTS coaching in Madurai

mama ji said...

Learn digital marketing skills to implement them on your website and social media to generate traffic and get maximum ROI. We teach 50+ modules in our Masters in Digital Marketing Course along with 02 Months onboard mentorship training session under our expets digital marketers for Students, Working Professionals, and Entrepreneurs.
netgear login/

pikashow.ltd

Anonymous said...

Hi, we are Kay Iron Works At Kay Iron Works, we are pioneers in manufacturing and supplying top-of-the-line industrial plant machines such as sugar plant machines cement and fertiliser plants, paper plants, material handling machines, telecom machinery, EOT cranes and waste tyre pyrolysis plant manufacturer in india. That drive the wheels of progress. With a legacy spanning decades, our company stands tall as a beacon of engineering excellence. Now, we extend our reach to the digital realm, crafting compelling social media profiles for businesses across the globe. Embracing innovation, we leverage our industry expertise to curate engaging content, foster meaningful connections, and amplify brand presence. Trust Kay Iron Works to forge a powerful online identity that reflects the strength and reliability of your industrial operations. Together, we build a brighter future for your business.

Social Media Marketing Services said...

Explore top-notch Search Engine Marketing services tailored to boost your online presence and drive targeted traffic. Our experts deliver effective SEM strategies for maximum ROI. Get started today!

The Assignment Helpline said...


Looking for reliable coursework writing services ? Our article explores the benefits of professional assistance, tips for choosing the right service, and how it can enhance your academic performance.

joe said...

Is your Linksys Router not connecting to internet ? Well, power cycle the Linksys router by first powering it off, and unplugging its power cord from the power source. Then, plug everything back into the original position after 10 seconds.

Alliance organics said...

Alliance Organics LLP is a top Basic Dyes Manufacturer in India. Our highly developed infrastructure makes research, cultivation, and development of superior quality basic dyes feasible which are further processed as per the client’s needs. Basic Dyes manufacturers in India, provide you with the best in all basic dyes requirements all across the country. Alliance Organics LLP is a big manufacturer of Basic Dyes in Powder Form and Basic Dyes in Liquid Form for the Paper industry, Ink industry and Plastic industry.

raju55 said...

I know what kind of feeling you are going through now. Excitement and Fear at one stage. Anyways Good Luck! Wish you all the Best!
Mathura Vrindavan Haridwar Tour Packages

electrician in orange said...

Reading this post brought back memories of when I tried creating a portable wrapper for another system call. I had a challenging time abstracting OS-specific errors, especially between POSIX and Windows. Chris's deep dive into custom error conditions in C++ offers invaluable insights, particularly the steps on establishing equivalence.

raj123 said...

it's patient to have to wait, but I'm sure it'll be fine! it is important to think positively and believe in your own abilities. good luck with the book!
popular tattoo styles

Kitchen Light said...

This blog post brought back memories of when I first started delving into error handling in C++ during my early programming days. Chris, your detailed breakdown of the facility and the nuances between error_code and error_condition has added great clarity to an often overlooked aspect of C++ programming. I'll definitely be incorporating your insights into my next project to make my error handling more robust and user-friendly.

Unknown said...

Greetings, I'm Selena Gomeez. I work at the airline office and am very knowledgeable about flights and airlines. People frequently ask me How to cancel a Vueling flight . Please check out my page; I hope it's helpful.

QSS Technosoft said...

Hi dear,

I recently came across your insightful blog post.As a team at QSS Technosoft, we are always on the lookout for valuable content that aligns with our interests and expertise.I really enjoyed reading it. I am waiting for your next post.

Thank You

W : Hire Flutter programmers.

brownmaeila said...

You must proceed with the wyze camera login to set up the camera correctly. You can only set up the camera through the user interface of the camera. All you need to do is install the Wyze app on your smartphone. Just open the app and log into your account. If you don’t have an account, create one and set up the camera.

brownmaeila said...

For Zmodo Camera Setup , you must first download the Zmodo app from the App Store or Play Store. Then launch the app and the login page will appear in your device’s screen. Next, fill in the login credentials in the login page and click on the ‘Log In’ button. Afterwards, you can start the configuration process.

brownmaeila said...

You can log in to your Linksys router by first opening a web browser on your device. Then enter 192.168.1.1 in the URL bar and the Linksys router login page will open. Consequently, enter the admin username & password in the respective fields and hit the Enter button. Finally, the Linksys router login is complete.

brownmaeila said...

The roborock Not Connecting to wifi is a serious issue that several users face. This issue could arise due to various reasons. Check your router and ensure the router is working properly. Issues within the router can also cause connectivity problems. You can try resetting your vacuum as well.

brownmaeila said...

Logging into nest camera is a very easy process. First, open the ‘Nest’ app and tap ‘Sign In with Nest’ on the screen’s bottom. Then fill in your admin username & password in the available spaces, and tap on ‘Sign In’. Congratulations, you have finally logged into Nest Camera.

adelina said...

Do you want to how to Reset Linksys extender ? Well, it’ll help you to ensure seamless connectivity by following some easy instructions. But you should know that it will erase all the user information. Moreover, it will set your Linksys extender to the default factory mode. For expert guidance & personalized assistance, chat with our dedicated technical experts right away.

adelina said...

The Linksys Velop keep disconnecting is an issue that many users come across. This issue arises when the Linksys velop has trouble connecting to the nodes or the internet. You need to check the distance between the Velop and the nodes. Too much distance will cause issues with the Linksys Velop.

Muqqabla Local Shopping said...

Muqqabla provides the best salons in Bangalore. Download the app and enjoy the offers

oasisnisha said...

Make this Lohri delightful for your near and dear ones, and gift Our  Special Lohri hampers at oasisbaklawa

Homecare01 said...

Our technicians are certified experts in LG microwave repairs in Delhi, ensuring your appliance is in capable hands.

«Oldest ‹Older   401 – 427 of 427   Newer› Newest»