Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a non-throwing function pointer point to a throwing-function?

On C++ Primer on noexcept exception specification, it is said that a pointer to a function that may throw Implicitly (defined without exception specification e.g: void(*p)();) or explicitly (void(*p)() noexcept(false);) may point to any function even to a non-throwing function.

On the other hand a function pointer which may not throw (noexcept e.g void(*p) noexcept;) can only point to a function that won't throw.

I found that very logical because the first pointer it is OK to point to a non-throwing function from a throwing function pointer and the second too is so logical.

I've tried this to understand more:

void func1(){ // may throw
    std::cout << "func1()\n";
}

void func2() noexcept(false){ // may throw
    std::cout << "func2()\n";
}

void func3() noexcept(true){ // won't throw
    std::cout << "func3()\n";
}

void func4() noexcept{ // won't throw
    std::cout << "func4()\n";
}


int main(int argc, char* argv[]){

    void(*pFn1)();
    pFn1 = func1; // OK
    pFn1 = func2; // OK
    pFn1 = func3; // OK
    pFn1 = func4; // OK

    void(*pFn2)() noexcept(false);
    pFn2 = func1; // OK
    pFn2 = func2; // OK
    pFn2 = func3; // OK
    pFn2 = func4; // OK

    void(*pFn3)() noexcept(true);
    pFn3 = func1; // Error on C++ 17 and above. OK on C++11 and 14
    pFn3 = func2; // Error on C++ 17 and above. OK on C++11 and 14
    pFn3 = func3; // OK
    pFn3 = func4; // OK

    void(*pFn4)() noexcept(true);
    pFn4 = func1; // Error on C++ 17 and above. OK on C++11 and 14
    pFn4 = func2; // Error on C++ 17 and above. OK on C++11 and 14
    pFn4 = func3; // OK
    pFn4 = func4; // OK

    std::cout << '\n';
}
  • When I compile the program against -std=c++17, -std=c++2a it works as it should so I get the errors as I've written in the lines comments. But when I compile against -std=c++11, -std=c++14 I get them all work and the compiler doesn't complain?!

Does this mean the standard has changed? Thank you!

like image 459
Maestro Avatar asked Mar 10 '21 23:03

Maestro


People also ask

Can pointers point to anything?

Any pointer can refer to any location in memory, so technically the statement is correct. With that said, you need to be careful when reinterpreting pointer types. A pointer basically has two pieces of information: a memory location, and the type it expects to find there. The memory location could be anything.

What Cannot be done with function pointer?

What will we not do with function pointers? Explanation: As it is used to execute a block of code, So we will not allocate or deallocate memory.

Can a pointer point to a function C++?

C++ allows you to pass a pointer to a function. To do so, simply declare the function parameter as a pointer type.

What happens if a Noexcept function throws?

When an exception is thrown from a function that is declared noexcept or noexcept(true) , std::terminate is invoked. When an exception is thrown from a function declared as throw() in /std:c++14 mode, the result is undefined behavior. No specific function is invoked.


1 Answers

It's ill-formed in C++17 because the noexcept is part of the type system, and there is no conversion from a pointer to a potentially-throwing function to a pointer to a non-throwing function.

Before C++17 the relevant rule is [except.spec] p5:

A similar restriction applies to assignment to and initialization of pointers to functions, pointers to member functions, and references to functions: the target entity shall allow at least the exceptions allowed by the source value in the assignment or initialization.

So although the noexcept isn't part of the type system, the OP's assignments are ill-formed.

G++ does not give an error for the example in p5:

class A { /* ... */ };
void (*pf1)(); // no exception specification
void (*pf2)() throw(A);

void f() {
  pf1 = pf2; // OK: pf1 is less restrictive
  pf2 = pf1; // error: pf2 is more restrictive
}

That should be ill-formed in C++98/11/14.

The equivalent with a noexcept-specifier would be:

class A { /* ... */ };
void (*pf1)(); // no exception specification
void (*pf2)() noexcept;

void f() {
  pf1 = pf2; // OK: pf1 is less restrictive
  pf2 = pf1; // error: pf2 is more restrictive
}

G++ doesn't reject this in 98/11/14, only C++17 and up.

like image 55
Jonathan Wakely Avatar answered Oct 16 '22 19:10

Jonathan Wakely