Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does C++'s exception not provide the calling details?

Tags:

c++

#include <fstream>
#include <iostream>
#include <map>

int main(int argc, char** argv) {
    try {
        std::map<std::string, int> m{{"a", 1}, {"b", 2}};
        std::cout << m.at("c") << std::endl;
    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
    }

    return 0;
}

In C++, when retrieving a non-existent key of a map, the exception looks like map::at: key not found. Information about what the key is is not provided.

Also, if one is accessing a non-existent file, the exception message of std::ios_base::failure looks like ios_base::clear: unspecified iostream_category error. The filename which caused the exception is not provided. Thus it may take quite a time to find out where the exception is from if there are many map.at() or ifstream is uses in a project.

In contrast to this, Python may tell you KeyError: 'c' or FileNotFoundError: [Errno 2] No such file or directory: 'foo'.

Is this just a C++ convention? Thank you.

like image 785
Saddle Point Avatar asked Dec 27 '17 07:12

Saddle Point


People also ask

What happens when an exception occurs?

Definition: An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program's instructions. When an error occurs within a method, the method creates an object and hands it off to the runtime system.

What happens when an exception is thrown C#?

In C#, the catch keyword is used to define an exception handler. If no exception handler for a given exception is present, the program stops executing with an error message.

What is exception call?

The term exception is shorthand for the phrase "exceptional event." Definition: An exception is an event that occurs during the execution of a program that disrupts the normal flow of instructions during the execution of a program.

What happens when you don't handle an exception?

if you don't handle exceptions When an exception occurred, if you don't handle it, the program terminates abruptly and the code past the line that caused the exception will not get executed.


2 Answers

The issue is the C++ object model, which differs from Python's. To contrast, first let's answer: what does Python store in the exception object to print the key? It's a reference that keeps that object alive.

This cannot be done simply in C++.

  1. std::out_of_range can't store a pointer or reference to the key as is. The handler for the exception may be in far away block. And that means that the key most probably went out of scope before the handler is entered. We get undefined behavior if the key is referred to.

  2. std::out_of_range is a concrete class. Not a template like std::map. It can't easily copy the key into itself. There are many different Key types, and it obviously can't account for all of them. Even if it could, what if the key is extremely expensive to copy? Or even non-copyable at all? Even in cases where that's not true, what if the key isn't convertible to a string, or printable?

The above points don't mean it's impossible. std::map::at can throw a sub-class of std::out_of_range that does type erasure and so forth. But I hope you see it has non-trivial overhead. C++ is all about not paying in performance for features you don't need or use. Making everyone bear that overhead unconditionally isn't in line with this design.

like image 133
StoryTeller - Unslander Monica Avatar answered Oct 09 '22 11:10

StoryTeller - Unslander Monica


C++ standard specifies that map::at(const key_type& k) will launch a std::out_of_range exception (if value is not inside it); nothing more... but nothing less; a particular implementation of map::at() but the problem would be that the k's key_type have to be converted to char*. So there are several options:

  1. Do not show this information
  2. std::map does not store types without (at least implicit) conversion to char*: but there would be a requirement applied to the key_store type that is not strict necessary
  3. To provide different messages in std::out_of_range exception depending on the key_type: but this solution does not always show the expected information

In other point of view, std::out_of_range inherits from std::logic_error; C++ standard distinguishes between two main types of exceptions:

  • logic_error: they are due to errors in the internal logic of the program. In theory, they are preventable.
  • runtime_error: they are due to events beyond the scope of the program. They cannot be easily predicted in advance.

In our case, we can check the existence of an element easily (so our case fixes with this case)

like image 38
Jogechu Caicoya Avatar answered Oct 09 '22 09:10

Jogechu Caicoya