Some functions should be non-throwing, but the standard doesn't say anything about it. Such as erase(q)
(q
denotes a valid dereferenceable constant iterator) of associative containers. This allows the implementation to throw any standard exception, according to [res.on.exception.handling#4]:
Functions defined in the C++ standard library that do not have a Throws: paragraph but do have a potentially-throwing exception specification may throw implementation-defined exceptions.170 Implementations should report errors by throwing exceptions of or derived from the standard exception classes ([bad.alloc], [support.exception], [std.exceptions]).
So if you want to swallow any implementation-defined exceptions they throw, you have to use a try-catch block.
std::set<int> s{1};
try
{
s.erase(s.cbegin());
}
catch (...) {}
It's ugly and inefficient, but necessary. So I also don't know of any benefit to this.
Here is a paper (quoted by some other standard library proposals) for reasons to not specify noexcept
on some standard library functions: N3248: noexcept
Prevents Library Validation
If a function that the standard says does not throw any exceptions does throw an exception, you have entered undefined behaviour territory. There is a bug in your code. Catching and swallowing it is certainly not the right thing to do.
For example in this code:
std::set<int> s;
try
{
s.erase(s.cbegin());
}
catch (...) {}
may make s.erase
throw a C++ exception in debug mode since the preconditions are not met (s.cbegin()
is not dereferenceable), making this run and seem to work unnoticed, but suddenly some other behaviour happens (like a crash or an infinite loop) in release mode.
If the standard mandated that this function was noexcept
, the function could not throw an exception even in debug mode.
However, standard libraries are allowed to add noexcept
specifiers even if not explicitly stated in the standard, which many do. This gives the freedom for a standard library implementor to do what is appropriate (e.g., noexcept(true)
in <release_set>
, but noexcept(false)
in <debug_set>
)
And, of course, if you know the preconditions are met (like if (!s.empty()) s.erase(s.cbegin());
), you know an exception can't be thrown and don't need to write any exception handling.
See also: Why vector access operators are not specified as noexcept?