Alexey Teplyakov
Alexey Teplyakov

Reputation: 316

Type casting in exceptions

Let's say I Have this:

namespace MyNamespace{

class Exception : public std::runtime_error
{
public:
  explicit Exception(const std::string &msg) : std::runtime_error(msg) {}
};

} //namespace MyNamespace

And there is a code somewhere in my program:

try{
    foo();
}
catch (const MyNamespace::Exception &exc){
    std::cout << exc.what();
}

The question is (I want you to examine me) - will I catch the exception if I write in foo:

1) throw MyNamespace::Exception("Hello world!");

Here i think, yes, I will, because I definitely pointed out the type of exception(and it's necessary couse of "explicit" keyword) and std::string doesn't have "explicit" keyword which means I can throw "Hello world!" instead of std::string("Hello world!")

2) throw MyNamespace::Exception(std::string("Hello world!"));

obviosly, I will.

3) throw "Hello world!";

here i think, no, I won't, cause of keyword "explicit" presence.

4) throw std::string("Hello world");

no (same reason)

and 5) Whould I catch expections from the 3-4 cases if I didn't have explicit keyword? (I think yes)

update: 6) When the temporary object std::string will be created? At what point of time?

Upvotes: 0

Views: 210

Answers (3)

Tony Delroy
Tony Delroy

Reputation: 106096

From the wording in 3-5, you're obviously thinking that C++ attempts to match the throw to the catch statements as if it were picking the best match from overloaded functions to call. That's not the case. The throw statement is considered separately from any catch statements - indeed, you can compile the function foo and its throw statements before the catching code is written, so it can't choose to convert a std::string to some type the catching code ends up looking for... it might not know about that.

The type of value thrown depends entirely on the type of the parameter to throw, as it would be understood in the surrounding context if the expression appeared without throw. For example:

void foo()
{
     ...
     throw XXX;
}

...throws the same type as...

void foo()
{
     ...
     auto what_will_be_thrown = XXX;
     throw what_will_be_thrown;
}

Conversions like const char* to std::string are not applied when catching, although you can catch a derived type via a public base class (for references or pointers), and of course you can catch types using const references etc..

Re 6) - whatever the type of the value, it's created just before the Exception constructor is called, just as any for any other function call timing wise, but in this case the object being thrown may be constructed in a separate memory area from the normal call stack, such that it will survive the stack unwinding that happens while looking for a matching catch statement. Exactly how this is orchestrated by the compiler is not specified in the Standard though.

Upvotes: 2

Konrad Rudolph
Konrad Rudolph

Reputation: 545588

Your rationale for 3 and 4 is wrong, and consequently, so is your answer to 5. Here’s why:

When you catch an exception, no conversion is every performed, except a conversion to base class. So catch (Foo const&) will never catch anything convertible to Foo, except subclasses of Foo. It’s for that reason, and not related to explicit constructors, that your code won’t catch a thrown std::string or char[].

Upvotes: 1

jrok
jrok

Reputation: 55395

Your answers for 1-4 are correct, but the reasoning behind them is a little off.

3) This has nothing to do with explicit keyword. The type of the expression after throw is const char[12] and by the rules the type of the exception thrown is const char*.

4) Again, nothing to do with explicit string constructors, really. The type thrown is std::string and only std::string (with reference or not) type of handler can catch it.

5) So obviously, no.

6) When the exception is thrown.

Upvotes: 2

Related Questions