Why vector access operators are not specified as noexcept?
The standard's policy on noexcept
is to only mark functions that cannot or must not fail, but not those that simply are specified not to throw exceptions. In other words, all functions that have a limited domain (pass the wrong arguments and you get undefined behavior) are not noexcept
, even when they are not specified to throw.
Functions that get marked are things like swap
(must not fail, because exception safety often relies on that) and numeric_limits::min
(cannot fail, returns a constant of a primitive type).
The reason is that implementors might want to provide special debug versions of their libraries that throw on various undefined behavior situations, so that test frameworks can easily detect the error. For example, if you use an out-of-bound index with vector::operator[]
, or call front
or back
on an empty vector. Some implementations want to throw an exception there (which they are allowed to: since it's undefined behavior, they can do anything), but a standard-mandated noexcept
on those functions makes this impossible.
Is array::operator[] actually noexcept?
The reason that operator[]
is not marked as noexcept
is that it has a "narrow contract", i.e, the index value is required to be in the range 0 ... N-1
. If the value passed is not in that range, the behavior is not defined, and (who knows?) the function might throw.
The standard is pretty consistent about not marking things with "narrow contracts" as noexcept. This is informally known as "the Lakos rule".
Note that library IMPLEMENTERS have the freedom to add noexcept
where the standard does not specify it, if they choose. I'll think about adding that to libc++.
[Later: It turns out that libc++ does this already for string
and string_view
, but not vector
, array
or deque
]
[Sill later: libc++ now marks operator[]
as noexcept for vector
/array
and deque
.]
Why are std::array::front and std::array::back not noexcept?
From cppreference
There is a special case for a zero-length array
(N == 0)
. In that case,array.begin() == array.end()
, which is some unique value. The effect of callingfront()
orback()
on a zero-sized array is undefined.
So since we can have a 0 sized array front()
and back()
could cause an exception
To quote Sebastian Redl on why the standard doesn't mandate operator[]
, front
and back
be marked noexcept
The standard's policy on
noexcept
is to only mark functions that cannot or must not fail, but not those that simply are specified not to throw exceptions. In other words, all functions that have a limited domain (pass the wrong arguments and you get undefined behavior) are notnoexcept
, even when they are not specified to throw.
Why some C++ standard functions are missing literal exception specification or not marked as conditionally noexcept?
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?
Should a function which can fail only due to integer overflow be noexcept?
As far as I know, noexcept should be interpreted as "nofail"
That's not correct. noexcept
literally means "I promise this function will never throw an exception." There are myriad other types of failures, such as segmentation faults, illegal instructions, the calling of pure virtual functions, integer divide by zero, not to mention "Bob in accounting told me all our customer numbers consist only of digits, but I just found out our very first customer's ID was actually Q001 and it doesn't parse." None of those will necessarily result in an exception, and neither will signed integer overflow, so functions failing in those ways can still be noexcept
even though they can fail--they just can't throw C++ exceptions.
You may then wonder, "What happens if an exception is thrown by a noexcept
function?" In that case, std::terminate()
will be called, and your program will end.
C++ exception, undefined behavior and noexcept
Should I define it as
noexcept
?
You certainly can, if you want. It is true in that the function won't throw an exception. It still can fail from division by zero, however.
It depends on what you think noexcept
should mean. The standard library seems to treat it as a keyword meaning the function can't possibly fail, not just that it doesn't throw. If you follow their convention, you shouldn't make it noexcept
. However, if you want noexcept
to mean only that it doesn't throw, then you should.
Either way, you should always use the same convention. Outside of constructors and assignment operators, there isn't a large benefit either way.
Why std::map find() is not declared as noexcept?
find()
are based on the Compare()
method of the map, that could throw an exception (imagine the case of a complex key that could be incorrect). So, we can not be sure that find()
won't raise an exception.
Related Topics
Is There a Reason Why Not to Use Link-Time Optimization (Lto)
Qapplication in Non-Main Thread
Avoid Exponential Grow of Const References and Rvalue References in Constructor
What Exactly Is Va_End For? Is It Always Necessary to Call It
Qt 5.5 Embed External Application into Qwidget
Inet_Pton': Identifier Not Found
Returning a "Null Reference" in C++
C++ Reading Unsigned Char from File Stream
Vector: Initialization or Reserve
Convert a Number to a String with Specified Length in C++
Error Lnk2005: New and Delete Already Defined in Libcmtd.Lib(New.Obj)
How to Determine Programmatically If an Expression Is Rvalue or Lvalue in C++
Why Copy Constructor Is Called When Passing Temporary by Const Reference
Why Define Operator + or += Outside a Class, and How to Do It Properly
Partial Ordering with Function Template Having Undeduced Context