#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.
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.
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.
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.
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.
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++.
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.
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.
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:
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 necessarystd::out_of_range
exception depending on the key_type: but this solution does not always show the expected informationIn other point of view, std::out_of_range
inherits from std::logic_error
; C++ standard distinguishes between two main types of exceptions:
In our case, we can check the existence of an element easily (so our case fixes with this case)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With