Here is main():
int main()
{
B b(1,"two","three");
try
{
f1(b);
}
catch(B& b_ref)
{
cout<<"Caught B&"<<endl;
b_ref.print();
}
catch(A& a_ref)
{
cout<<"Caught A&"<<endl;
a_ref.print();
}
system("pause");
return 0;
}
Here is f1():
void f1(A& subject)
{
throw subject;
}
Information:
B inherits from A. A::print() is virtual, and is reimplemented in B. The catch that catches the exception is catch(A& a_ref), which I guess makes sense, since the exceptions' static type (subject) is A&. BUT, why isn't B:: print() running? Is the dynamic type "lost"? Only A::print() runs in the line a_ref.print();.
Can somebody explain?
throw only throws an object of the type of the expression which follows it. In this case, subject is of type A&, regardless of what the actual object is, so an A is thrown (note that references cannot be thrown, so a copy is made).
You can deal with this by adding a member function to your exception classes which throws the exception. As long as you implement this method in every class, the override which gets called will know the runtime type of the object and can throw *this.
http://www.ddj.com/cpp/184401940
According to C++ standard 15.1/3:
A throw-expression initializes a temporary object, called the exception object, the type of which is determined by removing any top-level cv-qualifiers from the static type of the operand of throw...
So you create temporary object of type A, not B.
When you say "throw subject" a new exception object is created based on the static type of the throw expression (subject). The fact that subject is a reference is irrelevant for the purposes of determining what object to throw. A new A object is copy constructed from subject. This copy (or possibly a copy of this copy) is the actual object that is caught.
Catch blocks work polymorphically, but throw doesn't. When you say:
void f1(A& subject)
{
throw subject;
}
you are throwing an A, although the thing passed to the function is a B.
Because you catch by reference the object is 'sliced'.
If you really want polymorhpic behaviour, try using something like the pimpl idiom.
Related
I came from c++98, and i am trying to make my way in to c++11 and so on. i came across the public member function , std::exception::what, <=> virtual const char* what() const noexcept;
from this example givin in c++ reference : what_example, i can understand the usage but i have a few questions:
// exception::what
#include <iostream> // std::cout
#include <exception> // std::exception
struct ooops : std::exception {
const char* what() const noexcept {return "Ooops!\n";}
};
int main () {
try {
throw ooops();
} catch (std::exception& ex) {
std::cout << ex.what();
}
return 0;
}
in c++98 the what() was : virtual const char* what() const throw();, and in c++11, it becomes virtual const char* what() const noexcept;. what is the noexcept at the end? did it bring something new?
why should i use what() it at all? i can emplement my own tostring method in my class exception and call it instead!
in the return value of what(), see below, guaranteed to be valid at least until...or until a non-const member function of the exception object is called. what is the meaning of or until a non-const member function of the exception object is called, could some one explain with example and why is that ?
what() return value
A pointer to a c-string with content related to the exception. This is
guaranteed to be valid at least until the exception object from which
it is obtained is destroyed or until a non-const member function of
the exception object is called.
thanks.
what is the noexcept at the end?
It is a new specifier introduced in C++11. In very short, it means that the function will not throw an exception. noexcept has same meaning as throw().
did it bring something new?
noexcept is an improvement over the old throw specifier, which has since been deprecated (C++11) and then removed (C++20) from the language. It accepts a boolean expression that determines whether the function is noexcept or potentially throwing. This is useful in generic template programming because some instances of a template may be potentially throwing while others might not be.
why should i use what() it at all? i can emplement my own tostring method in my class exception and call it instead!
Because you may be using functions that are not written by you, and therefore will not throw your exception class. For example, some standard functions will in some cases throw an exception, and all standard exceptions derive from std::exception. In such case, the only way to access the error message is through the what member function.
Same applies when other people call your function. They might not want to / or need to know about your special exception class, but they can still catch it and print the message if you inherit std::exception.
what is the meaning of or until a non-const member function of the exception object is called
The meaning is literal. If you call what on an exception object derived from std::exception, and store the returned pointer, and then call a non-const member function of that exception object then the stored pointer will be invalid.
Any attempt to indirect through an invalid pointer such as attempting to print the exception message will result in undefined behaviour.
For your first question check out StoryTeller's comment. As for the second point:
why should i use what() it at all? i can emplement my
own tostring method in my class exception and call it instead!
The first rule of programming is do not reinvent the wheel, if there is a toString function or another function in the STL library that meets your needs, use it. Do not invent your own and try to debug it.
As an addition to the third question:
Sometimes, one happens to be surprised how important it can be that the wheel is not reinvented; and sharing the same basic class can be a big deal.
Thus, there comes a std::cerr message showing the contents of what, when the program crashes because of a thrown exception.
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?
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.
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.
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[].
Does the standard have anything to say about an exception that is caught by reference and what happens to attempts to modify it?
Consider the following code:
class my_exception: public std::logic_error
{
public:
std::vector<std::string> callstack;
};
void MyFunc()
{
try
{
SomethingThatThrows();
}
catch (my_exception & e)
{
e.callstack.push_back("MyFunc");
throw;
}
}
This is a contrived example, I'm not actually attempting something like this. I was just curious what would happen, based on the suggestion in another thread that exceptions should be caught by const reference.
The exception will change.
§15.3[except.handle]/17:
When the handler declares a non-constant object, any changes to that object will not affect the temporary
object that was initialized by execution of the throw-expression.
When the handler declares a reference to
a non-constant object, any changes to the referenced object are changes to the temporary object initialized
when the throw-expression was executed and will have effect should that object be rethrown.
So if my_exception is caught outside of MyFunc, we'll see the "MyFunc" entry in the callstack (e.g. http://ideone.com/5ytqN)
Yes, you can do this.
When you rethrow the current exception using throw;, no copies are made: the original temporary exception object is rethrown. Thus, any changes you make to that object in the handler will be present in the exception object when you next catch it.
I've just fixed a very subtle bug in our code, caused by slicing of an exception, and I now want to make sure I understand exactly what was happening.
Here's our base exception class, a derived class, and relevant functions:
class Exception
{
public:
// construction
Exception(int code, const char* format="", ...);
virtual ~Exception(void);
<snip - get/set routines and print function>
protected:
private:
int mCode; // thrower sets this
char mMessage[Exception::MessageLen]; // thrower says this FIXME: use String
};
class Derived : public Exception {
public:
Derived (const char* throwerSays) : Exception(1, throwerSays) {};
};
void innercall {
<do stuff>
throw Derived("Bad things happened!");
}
void outercall {
try {
innercall();
}
catch(Exception& e)
{
printf("Exception seen here! %s %d\n", __FILE__, __LINE__);
throw e;
}
}
The bug was of course that outercall ends up throwing an Exception, instead of a Derived. My bug resulted from higher in the call stack attempts to catch the Derived failing.
Now, I just want to make sure I understand - I believe that at the 'throw e' line, a new Exception object is being created, using a default copy constructor. Is that what's really going on?
If so, am I allowed to lock out copy constructors for objects that will be thrown? I'd really prefer this not happen again, and our code has no reason to copy Exception objects (that I know of).
Please, no comments on the fact that we have our own exception hierarchy. That's a bit of old design that I'm working to correct (I'm making good progress. I've gotten rid of the home-grown string class, and many of the home-grown containers.)
UPDATE: To be clear, I had fixed the bug (by changing 'throw e' to 'throw') before I ever asked the question. I was just looking for confirmation of what was going on.
When you throw an object, you're actually throwing a copy of the object, not the original. Think about it - the original object is on the stack, but the stack is being unwound and invalidated.
I believe this is part of the standard, but I don't have a copy to reference.
The type of exception being thrown in the catch block is the base type of the catch, not the type of the object that was thrown. The way around this problem is to throw; rather than throw e; which will throw the original caught exception.
A quick google suggests that yes, you're throwing the copy constructor is required and must be public. (Which makes sense, as you're initializing a copy of e and throwing that.)
Anyway, just use throw without specifying the exception object, to rethrow what was caught in the catch. Shouldn't that solve the problem?
catch(Exception& e)
{
printf("Exception seen here! %s %d\n", __FILE__, __LINE__);
throw;
}
Yes.
throw e;
throws an exception of the static type of e, regardless of whatever e actually is. In this case, the Derived exception is copied to an Exception using a copy constructor.
In this case you can just
throw;
to get the Derived exception bubble up correctly.
If you're interesting in polymorphical throwing in some other cases, refer to the always so useful C++ FAQ Lite.
C++ never ceases to amaze me. I would have lost a lot of money had this been a bet on what was the behaviour!
The exception object is first copied to a temporary and you should have used throw. To quote the standard 15.1/3:
A throw-expression initializes a temporary object, called the exception object, the type of which is determined by removing any top-level cv-qualifiers from the static type of the operand of throw and adjusting the type from "array of T" or "function returning T" to "pointer to T" or "pointer to function returning T",respectively.
I think this gives rise to a very useful coding standard rule:
Base classes of an exception hierarchy should have a pure virtual destructor.
or
The copy constructor for a base class in an exception hierarchy shall be protected.
Either achieves the goal that the compiler will warn when you try to "throw e" since in the first case you cannot create an instance of an abstract class and the second because you cannot call the copy constructor.
Have a class with couple of integers and a pointer ,
class A {
int a;
int b;
char* s;
public:
...
class ConstructA {
A &a;
public:
ConstructA (A& ta) : a(ta) {}
...
};
};
As seen ConstructA is responsible for constructing object A.
I want to write a method to see if ConstructA was successful in constructing the object a. How would you go about it ?
Since there is no way for a constructor to fail in C++, an object either:
does not exist
is successfully constructed.
If a constructor throws an exception, the object effectively does not exist at the point the exception is caught.
You may want to implement an additional method such as isOK() that returns whether or not the internal state of the object represents something useful. For example, if you have an object that represents a file, then you could use isOK() to indicate that the file could be successfully opened. However, as far as C++ is concerned, the file object would be fully constructed whether or not the file could be opened.
Having said that, I'm not entirely sure what the role of the ConstructA class is in your example.
As a general rule, if there is any failure in construction you will get an exception thrown -- either a program-specific exception from the object itself, or else a memory exception or something similar from the runtime.
In this particular case, you are not constructing an object of type A, you are initializing a reference. So there is no construction that has an opportunity to fail.
(Perhaps a little more detail about what you are trying to accomplish would help somebody give a better answer?)
You're ConstructA is just trying to hold on to a reference of an already constructed A, try changing it to this:
class ConstructA {
A a; // Don't make this a reference
public:
ConstructA (A& ta) : a(ta) {}
...
};
First, your ConstructA class makes no sense at all to me. There really are two cases basically:
The construction of an object fails
The object is left in an defined, but restricted state. Strictly, the construction succeeded, but possibly not the the degree that the caller wished. He can optionally later complete the construction.
1. The construction fails
I'll use your ConstructA in the following code just to make the point of signaling about construction failure:
A a0;
try {
A::ConstructA a1(a0);
} catch(...) {
// fail to construct a1
}
Constructors throw exceptions to signal when their constructions fail. The idea is that if construction of an object fails, then the object is not constructed. In other words, the object does not exist. If you have to initialize a1 in an constructor init list, there is a way too:
struct B {
B() try : a1(a0) {
// other constructor code...
} catch(...) {
// fail to construct either a0 or a1, or constructor
// code threw
}
A a0;
A::ConstructA a1;
};
try {
B b;
} catch(...) {
// fail to construct B
}
First, code in the catch block of the constructor is executed, then the exception is automatically propagated to the code that created the B object, and its catch blocks are considered.
Your class ConstructA's constructor could look like this, for example:
struct ConstructA {
ConstructA(A &a):a(a) {
if(!condition_met) {
throw std::runtime_error("condition_met false");
}
}
A &a;
};
2. The object is in a restricted state
That is exactly the case what you have when you have a file stream object, but which is not connected to a file. If in the constructor you find that the file mentioned doesn't exist, you can still fully construct the stream, but set it in a not-opened state. Some operations could be disallowed then and you can have a isOpen or isValid function that you can use to query the state of the object.
This can be applied to other cases too. Some framework i used has a Color class. Default constructing a color class left it in a invalid state, so that it doesn't compare equal to any valid color:
Color c;
assert(c.isValid() == false);
The same technique is used for a null pointer. It's set to a defined, but restricted state when you assign NULL to it:
int *a = NULL;
assert(a == NULL);
You cannot dereference a null pointer for example.
mkal, I always suggest people not to use exception in C++. It cause more problems that it tries to solve.
To answer your question, to avoid exception in C++, you probably can reduce the work you
want to do in your constructor, and create an init() method instead, that returns the error-code if something goes wrong.
Basically, whatever you do in C++ Constructor, it has to succeed.
Hope that helps.