Exception safety of std::function initialized by a function pointer - c++

The constructor of std::function is not declared noexcept:
template< class F > function( F f );
On the other hand, C++ reference mentions the following:
Does not throw if f is a function pointer or a std::reference_wrapper,
otherwise may throw std::bad_alloc or any exception thrown by the copy
constructor of the stored callable object.
Does it mean that the constructor of the following class can be safely declared noexcept since I initialize std::function with a pointer to a static member function?
class Worker
{
public:
Worker() noexcept {} // ok?
void test() { reporter("test"); }
private:
static void dummy(const std::string& ) {};
std::function<void (const std::string&)> reporter = &dummy; // doesn't throw an exception?
};
int main()
{
Worker w;
w.test();
}
And if std::function member were constructed from a lambda, declaring the constructor noexcept would be wrong?
class Worker
{
public:
Worker() noexcept {} // bad?
void test() { reporter("Test"); }
private:
std::function<void (const std::string&)> reporter = [](const std::string& ){}; // may throw?
};
I have also noticed that GCC gives an error when the constructor declared noexcept is defaulted, because its exception specification does not match the implicit exception specification, which is noexcept(false) due to std::function constructor not being declared noexcept.
class Worker
{
public:
Worker() noexcept = default; // this won't compile
void test() { reporter("test"); }
private:
static void dummy(const std::string& ) {};
std::function<void (const std::string&)> reporter = &dummy;
};

Does it mean that the constructor of the following class can be safely declared noexcept since I initialize std::function with a pointer to a static member function?
Note that it's always "safe" to declare a function noexcept. The program will terminate if an exception is thrown, but it isn't undefined behavior.
But yes, in your case, no exceptions should be thrown, so no termination of the program should happen. The standard says: "Throws: Nothing if f is ... a function pointer. ..."
And if std::function member were constructed from a lambda, declaring the constructor noexcept would be wrong?
Yes, it'd be "wrong" in the sense you want (the program will terminate if it throws), because a lambda isn't a function pointer. Instead, prefix the lambda with the unary operator+ to make it a function pointer:
std::function<void (const std::string&)> reporter = +[](const std::string& ){};
And I'd probably mention this in a comment, in particular if you did not comment why the constructor is noexcept.
I have also noticed that GCC gives an error when the constructor declared noexcept is defaulted
The latest versions of both GCC and Clang do not give an error, so if that is true it is perhaps a Defect Report that was issued on the standard.

Related

Deleting all rvalue function overloads of a class

Say I have a class object that must be captured by the caller when returning this class's object from a function call.
// no_can_rvalue *must* be captured
[[nodiscard]] no_can_rvalue a_func();
I can enforce this by deleting all rvalue function overloads, thus making it impossible to use the class functionality unless a caller has captured an object of it (doubled with nodiscard in c++17).
Is it possible to delete all rvalue function overloads of a given class in one fell swoop?
The result being equivalent to :
struct no_can_rvalue {
void f() && = delete;
void f() &;
void g() && = delete;
void g() &;
// etc
};
No, it is not possible to do so.

exception specification of overriding function is more lax than base version

I want to custom an Exception class, here's the code:
class TestException : std::exception{
public:
const char *what() const override {
return "TestException";
}
};
I used Clion and the IDE give me a warning on the function what():exception specification of overriding function is more lax than base version
But if I build the code with gcc, there's no warning came out.
I used c++ 14, gcc 6.5.0
Can anybody help to explain what does the warning mean and can I just ignore it?
what from std::exception is a virtual function and a virtual function in a derived class cannot have a laxer exception specification than the function it overrides in the base class.
This is mentioned in the section on "Exception specifications" in the standard.
18.4 Exception specifications [except.spec]
...
4. If a virtual function has a non-throwing exception specification, all declarations, including the definition, of any function that overrides that virtual function in any derived class shall have a non-throwing exception specification, unless the overriding function is defined as deleted.
And the example given (which is somewhat similar to the code in the question) illustrates this as well.
struct B
{
virtual void f() noexcept;
virtual void g();
virtual void h() noexcept = delete;
};
struct D: B
{
void f(); // ill-formed
void g() noexcept; // OK
void h() = delete; // OK
};
The declaration of D::f is ill-formed because it has a potentially-throwing exception specification, whereas B::f has a non-throwing exception specification.
The solution is to change your code like:
class TestException : std::exception{
public:
const char *what() const noexcept override {
return "TestException";
}
};
See compilation here.
what member function of std::exception is declared as noexcept since C++11. You should therefore make your overridden what noexcept as well. (Actually, this is what the error message says.)
Note that the noexcept keyword must come before the override keyword (see, e.g., The order of override and noexcept in the standard for details).
The warning you are facing is related to the fact that you are using C++14, if you would compile with C++17 this becomes an error. Hence I would not recommend ignoring it.
Whats going on?
std::exception defines the method what as: virtual const char* what() const noexcept;. You inherit from this method and you re-implement it without specifying noexcept. By result, you are telling that your implementation can throw exceptions, while the base method indicates this should never throw. (And callers will assume so)
This was fixed in C++17, which made noexcept part of the type system, and requires you to fix this code:
const char *what() const noexcept override

Why does a noexcept constructor require instantiation of the destructor?

In the following code, a wrapper<T> object is declared which contains a movable<T>, where T is an incomplete type. The destructor of movable is made so that it cannot be instantiated without complete knowledge of T, but wrapper's destructor is only forward-declared, which means that it should be sufficient if ~movable() is instantiated at the point of definition of ~wrapper().
#include <utility>
template<class T>
struct movable {
movable() noexcept = default;
~movable() noexcept { (void) sizeof(T); }
movable(const movable&) noexcept = delete;
movable(movable &&) noexcept = default;
};
template<class T>
class wrapper {
public:
movable<T> m;
wrapper() noexcept = default;
wrapper(wrapper &&) noexcept = default;
~wrapper();
};
struct incomplete;
int main() {
/* extern */ wrapper<incomplete> original;
wrapper<incomplete> copy(std::move(original));
}
(Try it here)
However, wrapper() wants to instantiate ~movable(). I get that in case of an exception, destruction of members must be possible, but movable() and wrapper() are both noexcept. Interestingly, the move constructor works fine (try uncommenting the extern part in the example code.)
What is the reason for this behaviour, and is there a way to circumvent it?
As observed by T.C.,
In a non-delegating constructor, the destructor for [...] each non-static data member of class type is potentially invoked [...]
Per DR1424, the motivation is to make it clear that an implementation is required to issue an error if a destructor is inaccessible from the constructor of the parent object, "[even if] there is no possibility for an exception to be thrown following a given sub-object's construction".
The destructor of movable<T> is accessible, but it cannot be instantiated, which is where your problem arises as a potentially invoked destructor is odr-used.
This makes life simpler for the implementor, as they can just verify that each subobject has an accessible and if necessary instantiable destructor, and leave it to the optimizer to eliminate destructor calls that are not required. The alternative would be horribly complicated - a destructor would be required or not required depending on whether any succeeding subobjects were noexcept constructible, and on the constructor body.
The only way to avoid potential invocation of the destructor would be to use placement new, taking over management of the lifetime of the subobject yourself:
#include <new>
// ...
template<class T>
class wrapper {
public:
std::aligned_storage_t<sizeof(movable<T>), alignof(movable<T>)> m;
wrapper() noexcept { new (&m) movable<T>; };
wrapper(wrapper&& rhs) noexcept { new (&m) movable<T>{reinterpret_cast<movable<T>&&>(rhs.m)}; }
~wrapper();
};

Using the noexcept operator to chain noexcept declarations

Why does the noexcept operator take an expression rather than a function signature/declaration?
Consider the following dummy example:
#include <string>
void strProcessor(const std::string& str) noexcept(true) { };
struct Type{
void method1() noexcept(strProcessor("")) { //Error: Call to nonconstexpr function
strProcessor("");
}
};
It won't compile because method1 has a non-constexpr expression in its noexcept, but why do I need to put an expression in there in the first place?
All I want to do is tell the compiler that method1 is noexcept iff an invocation of strProcessor with a succesfully constructed string is noexcept (which it is).
So why not noexcept(void strProcessor(const std::string&))?
Another similar dummy example:
struct Type{
Type(bool shouldThrow=false) noexcept(false) { if(shouldThrow) throw "error"; };
void method1() noexcept(true) {};
void method2() noexcept(noexcept(Type().method1())) { method1(); };
}
Here I'd like to say method2 is noexcept iff invoking method1 on a succesfully constructed instance of Type is noexcept (which it is in this case), but Type isn't even complete at the point where method2 id defined.
Please explain if my understanding of this feature is wrong.
void method1() noexcept(noexcept(strProcessor(""))) {
// Second 'noexcept' ^^^^^^^^^ ^
The first one is the noexcept specifier, which specifies whether or not method1() is noexcept.
The nested one is the noexcept operator, which checks whether strProcessor() is noexcept when called with "".
Your second case is a bit tricky : Type is still incomplete at the point we'd like to use method1() inside noexcept. I've come to the following workaround, abusing a pointer-to-member :
void method2() noexcept(noexcept(
(std::declval<Type>().*&Type::method1)()
)) {};
However, I don't think there's a case where you could only deduce method2()'s noexcept specification from that of method1().
If you want some syntactic sugar when checking the noexceptness of a function, you can use an auxiliary function like so:
template <typename R, typename... Params>
constexpr bool is_noexcept(R(*p)(Params...)) {
return noexcept(p(std::declval<Params>()...));
}
And apply thusly:
void method1() noexcept(is_noexcept(strProcessor)) …
Demo.

What the c++ standard says about loosing throw specifier in default destructor

Three different compilers show three different behaviours compiling this code:
class MyException : public std::exception
{
public:
MyException(std::string str) : m_str(str) {}
virtual const char * what() const throw () {return m_str.c_str(); }
protected:
std::string m_str;
};
Sun C++ 5.8 Patch 121017-22 2010/09/29: Warning Function MyException::~MyException() can throw only the exceptions thrown by the function std::exception::~exception() it overrides
g++ 3.4.3: Error looser throw specifier for `virtual MyException::~MyException()'
Visual Studio 2005: It is very happy (neither error or warning)
class exception {
public:
exception () throw();
exception (const exception&) throw();
exception& operator= (const exception&) throw();
virtual ~exception() throw();
virtual const char* what() const throw();
}
I know what the problem is and how I can fix it:
class MyException : public std::exception
{
public:
MyException(std::string str) : m_str(str) {}
virtual const char * what() const throw () {return m_str.c_str(); }
~MyException() throw() {} <------------ now it is fine!
protected:
std::string m_str;
};
However I am wondering what the standard says in specific situation.
I ran another small test in Visual Studio 2005 and I have found something that really surprise me:
struct Base
{
virtual int foo() const throw() { return 5; }
};
struct Derived : public Base
{
int foo() const { return 6; }
};
int main()
{
Base* b = new Derived;
std::cout << b->foo() << std::endl; //<-- this line print 6!!!
delete b;
}
The signature of the two functions are different. How can this work? It seems that visual studio 2005 completely ignore the exception specification.
struct Base
{
virtual int foo() const throw() { return 5; }
};
struct Derived : public Base
{
int foo() { return 6; } // I have removed the const keyword
// and the signature has changed
};
int main()
{
Base* b = new Derived;
std::cout << b->foo() << std::endl; // <-- this line print 5
delete b;
}
Is this c++ standard? Is there any magic flag to set?
What about VS2008 and VS2010?
Your program is ill-formed as per the C++ Standard and hence demonstrates a behavior which cannot be explained within the realms of the C++ standard.
Reference:
C++03 Standard:
15.4 Exception specifications [except.spec]
If a virtual function has an exception-specification, all declarations, including the definition, of any function that overrides that virtual function in any derived class shall only allow exceptions that are allowed by the exception-specificationof the base class virtual function.
[Example:
struct B
{
virtual void f() throw (int, double);
virtual void g();
};
struct D: B
{
void f(); // ill-formed
void g() throw (int); // OK
};
The declaration of D::f is ill-formed because it allows all exceptions, whereas B::f allows only int and double. ]
It evolved a bit in C++11 [except.spec]:
5/ If a virtual function has an exception-specification, all declarations, including the definition, of any function that overrides that virtual function in any derived class shall only allow exceptions that are allowed by the exception-specification of the base class virtual function.
So you are never actually allowed to specify a looser exception specification.
However this case is tricky because the destructor is actually synthetized by the compiler itself!
In C++03, I think the Standard was not so careful about those, and you had to write them yourself, in C++11 however we get:
14/ An implicitly declared special member function (Clause 12) shall have an exception-specification. If f is an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id T if and only
if T is allowed by the exception-specification of a function directly invoked by f’s implicit definition; f shall allow all exceptions if any function it directly invokes allows all exceptions, and f shall allow no exceptions if every function it directly invokes allows no exceptions.
Where the compiler will generate the exception specification of the destructor so that it matches what can be thrown from the functions it calls (ie, the destructors of the attributes). If those destructors do not throw, then it will generate a noexcept destructor which will satisfy the base class constraint.
Note: VS2005 is one of the least Standard compliant compiler you might find on Earth.