Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When does compiler mark default generated constructor as noexcept?

Tags:

c++

It seems like at modern versions of at least some compilers (GCC 5.2 and Visual C++ 2015 Update 1) incorrectly generate noexcept default constructors when there are initialized class members:

#include <memory>
#include <exception>
#include <iostream>

struct E {};

struct A
{
    A()
    {
        throw E();
    }
};

struct B
{
    A a;
};

struct C
{
    std::shared_ptr<B> b{ std::make_shared<B>() };
        //C() {}  // uncomment to fix
};

int main()
{
    try
    {
        new C;
    }
    catch (const E &)
    {
        std::cout << "Exception caught\n";
    }
    std::cout << "Exiting...\n";
}

Running this code causes std::terminate to be called (instead of invoking catch block) on GCC 5.2 (C++14 mode) and Visual C++ 2015 Update 1.

Live example: http://coliru.stacked-crooked.com/view?id=16efc34ec173aca7

Uncommenting empty constructor fixes this code for Visual C++, but not for GCC. Clang 3.6 correctly (I suppose?) calls catch block in any case.

Are there any rules in Standard that tell when the default generated constructor must be marked as noexcept?

like image 531
Alexander Bessonov Avatar asked Feb 10 '16 14:02

Alexander Bessonov


People also ask

Are default constructors Noexcept?

Inheriting constructors and the implicitly-declared default constructors, copy constructors, move constructors, destructors, copy-assignment operators, move-assignment operators are all noexcept(true) by default, unless they are required to call a function that is noexcept(false) , in which case these functions are ...

What does Noexcept mean in C++?

A noexcept-expression is a kind of exception specification: a suffix to a function declaration that represents a set of types that might be matched by an exception handler for any exception that exits a function.

What's the point of Noexcept?

The noexcept operator performs a compile-time check that returns true if an expression is declared to not throw any exceptions. It can be used within a function template's noexcept specifier to declare that the function will throw exceptions for some types but not others.

Which of the following are valid reasons for using the C++ keyword Noexcept?

The noexcept specification is part of the function type but can not be used for function overloading. There are two good reasons for the use of noexcept: First, an exception specifier documents the behaviour of the function. If a function is specified as noexcept, it can be safely used in a non-throwing function.


1 Answers

I'm going by C++14 here; I don't know if post-C++14 wording changes clarified the situation.

The problem is that the standard's language for generated noexcept specifications in the face of in-class initializers is rather unclear. The standard says for generated member functions in 17p14:

f allows all exceptions if any function it directly invokes allows all exceptions, and f has the exception-specification noexcept(true) if every function it directly invokes allows no exceptions.

However, "directly invokes" is not clearly defined in the standard, and is not obvious when it comes to in-class initializers. Your class C invokes std::make_shared<B> (which obviously can throw regardless of B's exception specification, as it allocates memory) and the copy constructor of std::shared_ptr<B> (which is noexcept) in its initializer, but do those count as "directly invoked", or does only the copy constructor count?

It may well be that this is where the compilers differ in interpretation. Clang appears to count make_shared, while the other compilers apparently don't.

Giving B a default constructor should change nothing, since that constructor is only called from within make_shared and is therefore definitely out of the view of the compiler; if it does change something, there's something seriously wrong.

However, giving C an empty, non-defaulted default constructor should most definitely mean that the constructor is not noexcept, and different behavior is definitely a bug.

like image 178
Sebastian Redl Avatar answered Sep 27 '22 22:09

Sebastian Redl