Re: Is there a good use case for noexcept?
I believe, it would be (3), with the annotation "DO NOT USE noexcept
EXPLICITLY". Really. This is not ironical.
[...]
1 and 2 from your list would not be good candidates and neither would
4, for the following reasons.
The fact that you can prove your function never throws an exception,
does not mean that it won't throw in the future.
suppose you have function:
void swap_potinters( int * lhs, int * rhs ) noexcept
{
int * tmp = lhs;
lhs = rhs;
rhs = tmp;
}
Now, suppose you need to add logging only for the time of debugging
void swap_potinters( int * lhs, int * rhs ) noexcept
{
LOG("swapping pointers");
int * tmp = lhs;
lhs = rhs;
rhs = tmp;
}
You get an error. A throwing function declared noexcept. You want to
remove noexcept now? This will require the recompilation of the entire
program.
It's a good example. But consider this; we are going into a new era of
making our applications even more robust than ever by means of noexcept
the way Abrahams' proposed (originating from his exception safety
guarantees). We have to rethink our new designs.
So how would I solve the above problem? I would reason like this; LOG
has nothing to do with swapping pointers, so it must not effect my
decision to use noexcept. Nevertheless, we want LOG to be there.
If I had the source code to LOG then I would make LOG noexcept as well.
If I did not have the source code I would do like this
void swap_pointers( int * lhs, int * rhs ) noexcept
{
try { LOG("swapping pointers"); }
catch( ... ) {}
int * tmp = lhs;
lhs = rhs;
rhs = tmp;
}
or, if LOG is a C function we know won't throw, use the noexcept block
that Martin B. talks about in the previous post "History and evolution
of the noexcept proposal?"
void swap_pointers( int * lhs, int * rhs ) noexcept
{
noexcept { LOG("swapping pointers"); }
int * tmp = lhs;
lhs = rhs;
rhs = tmp;
}
Now, many of you may rage over my choice to swallow the exceptions from
LOG with try/catch(...){}, but remember; LOG is *not* part of the
semantics of swap_pointers, hence, that's a legal design decision.
I find this discussion very productive. We must be clear on how to
reason when using noexcept. Please feel free to provide more arguments.
Now I see my example wasn't a good one. I failed to state my point.
First, I used name "swap" in function which brings std::swap to mind,
which in turn is a good candidate for noexcept. Second, I used
function LOG, which perhaps shouldn't even throw (I think Boost.Log
doesn't throw on failure).
So let me give you a different example. This one is literally taken
from http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3248.pdf.
Suppose I have the following function:
T& std::vector<T>::front() noexcept {
assert(!this->empty());
return *this->data();
}
Function front doesn't need to provide a no-fail guarantee, but we
labeled it with noexcept because we could. assert typically either
aborts or does nothing, so it works fine noexcept. But what if for
unit-test framework I want to change the meaning of assert to signal
test failure with an exception? (This argument is still taken from
n3248.pdf) This is just unit tests so I can decide to do it and this
is what unit-test frameworks usually do: try to also detect assertion
failures. So we would probably implement an assert as
#define assert(cond) \
static_cast<void>( cond || signalFailure(#cond __FILE_,
__LINE__) )
[[noreturn]]
bool signalFailure( string cond, string file, unsigned line )
{
throw TestFailure(cond, file, line);
}
Now the testing will not work, because the program will terminate as
soon as we try to signal test failure.
Regards,
&rzej
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]