Why does the compiler look for a default constructor for my exception class?

612 views Asked by At

I've defined a small exception hierarchy for my library. It inherits from std::runtime_error, like this:

class library_exception : public std::runtime_error {
    using std::runtime_error::runtime_error;
};

class specific_exception : public library_exception {
    int guilty_object_id;

    specific_exception(int guilty_object_id_)
        : guilty_object_id(guilty_object_id_) {}
};

The compiler says:

error: call to implicitly-deleted default constructor of 'library_exception'

and points to the specific_exception constructor.

Why is it trying to call the default constructor here?

2

There are 2 answers

0
juanchopanza On BEST ANSWER

library_exception inherits from std::runtime_error. The latter does not have a default constructor, which means the former isn't default constructable.

Similarly, specific_exception isn't default constructable because its base class isn't. You need a default constructor for the base here because the base is implicitly initialized:

specific_exception(int guilty_object_id_)
    : guilty_object_id(guilty_object_id_) {}

To fix this, call the appropriate base class constructor:

specific_exception(int guilty_object_id_)
    : library_exception("hello, world!"),
      guilty_object_id(guilty_object_id_) {}
1
Leif Arne Storset On

Retracted: This answer was misguided. (The constructors referred to are actually used in default initialization of class members, not the class itself.)

std::runtime_error has a string field, something like this:

class runtime_error {
    std::string msg;

public:
    runtime_error(std::string msg) : msg(msg) { }
};

msg is not initialized by your constructor (and can't be, since the field's private). Therefore the default constructor is invoked. More precisely,

default initialization […] is the initialization performed when a variable is constructed with no initializer.

Default initialization is performed in three situations:

3) when a base class or a non-static data member is not mentioned in a constructor initializer list and that constructor is called.

The effects of default initialization are:

If T is a […] class type, the constructors are considered and subjected to overload resolution against the empty argument list. The constructor selected (which is one of the default constructors) is called to provide the initial value for the new object.

(cppreference.com)

However, I still don't get why it's complaining about the base class library_exception instead of specific_exception. Adding an argument-less constructor in specific_exception doesn't make a difference.