Reputation: 316
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
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
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
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