Disclaimer: I suspect the trick described below is obvious, but I failed
to find any posts in this group which is referring to it, so I just
leave it here.
There was a big problem in C++03, when accepting template argument, you
know nothing about exceptions which can occur while you're using this
argument. Sometimes, this can lead to additional logic and performance
penalty.
As for me, I don't care about exceptions type, it is the caller who
should handle them. My job is to prevent resource leaks and I need to
know if execution sequence can be interrupted by exception.
In C++11 there is noexcept operator, which allows to determine if some
expression can throw an exception. From this, it is become possible to
provide two function implementations, one for exception throwing
argument, and second one with noexcept exception specification.
For example, consider class C with template c'tor which allocates some
resources and then calls member function f() of the argument. It is a
good practice to wrap resources with unique_ptr or something similar in
order to avoid resource leak, but this introduces slight overhead for
non-throwing arguments, which can be unacceptable in
performance-critical applications. So, public c'tor accepting argument
can delegate its work to one of the overloaded c'tors which accepts
std::true_type and std::false_type accordingly:
#include <type_traits>
#include <iostream>
struct A {
void f() {}
};
struct B {
void f() noexcept {}
};
class C {
template <class T>
C(T t, std::true_type) noexcept
{
t.f();
std::cout << "here we can use straight and simple logic here as no"
" exceptions are possible"<< std::endl;
}
template <class T>
C(T t, std::false_type)
try
{
// resources allocation here
// ...
t.f();
std::cout << "here we should use a bit more complicated logic
to avoid"
" resource and memory leaks" << std::endl;
}
catch (...)
{
std::cerr << "here we must free resources acquired" << std::endl;
}
public:
template <class T>
C(T t) noexcept(noexcept(t.f()))
: C(t, std::integral_constant<bool, noexcept(t.f())>())
{
}
};
int main()
{
A a;
B b;
C c(a);
C c2(b);
}
In the example above, we can delete c'tor overloading with false_type in
order to forbid throwing arguments.
Fly in the ointment:
Thoughts about such trick came to me when I worked on class which
accepts functor, which can be just a std::plus. Unfortunately helper
functors declared as:
T operator()(const T& x, const T& y) const;
Not as:
T operator()(const T& x, const T& y) const noexcept(x+y);
So, this reduces the area where this trick is applicable.
--
[ See
http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]