I'm learning exception handling in C++ and run into a problem. Here's the code:
#include<iostream>
#include<exception>
using namespace std;
class A
{
public:
virtual void f(void){}
};
class AA:public A
{
public:
void aa(void){};
};
int main(void)
{
A a;
try
{
dynamic_cast<AA>(a).aa();
}
catch(exception ex)
{
cout<<"["<<ex.what()<<"]"<<endl;
}
return 0;
}
So I thought the try catch will allow the function to execute and show me the content of the exception, but my compiler does not compile it. I'm using codeblock with GNU GCC. Please help me and show me what I need to do to get the code run as I intended. thanks a lot.
dynamic_cast can only cast to a pointer value or reference, which is exactly what the error is telling you.
From $5.2.7/1 of the C++ Standard.
The result of the expression dynamic_cast< T >(v) is the result of converting the expression v to type T. T shall be a pointer or reference to a complete class type, or “pointer to cv void.”
In order for dynamic_cast to throw an exception when the object cannot be converted you need to cast to a reference. Change it to the following:
dynamic_cast<AA&>(a).aa();
// ^^^ cast to reference.
As Johnsyweb pointed out dynamic_cast will always throw std::bad_cast when the conversion fails. Although std::bad_cast is derived from std::exception it is always a good idea to use the exception which best fits the expected fail condition. This prevents inadvertently interpreting other errors as an unsuccessful cast.
To apply this to your example it might look like the code below.
#include <iostream>
#include <typeinfo> // std::bad_cast
class A
{
public:
virtual void f(void){}
};
class AA:public A
{
public:
void aa(void){};
};
int main(void)
{
A a;
try
{
dynamic_cast<AA&>(a).aa();
}
catch(const std::bad_cast& ex)
{
std::cout << "["<<ex.what()<<"]" << std::endl;
}
return 0;
}
[Note, doing things like using namespace std; is strongly discouraged as it can cause conflicts with identifiers in the global namespace. I have removed it in the example above.]
You are getting a compiler error because your dynamic_cast is not on pointer or reference.
Change it to:
dynamic_cast<AA&>(a).aa();
... and you get the proper exception thrown.
On side note: Smart compilers like g++ would warn as well:
warning: dynamic_cast on an object (here a) can never succeed.
So it's better to limit such code for toying around. In production quality code, the dynamic_cast should be performed only on pointer/reference.
Your problem is not with exception handling, but with your dynamic cast:
'AA' is not a reference or pointer
dynamic_cast safely converts pointers and references to classes and not instances.
So you could do:
dynamic_cast<AA&>(a).aa();
...which will always fail and throw a std::bad_cast exception.
You should catch the most-specific type of exception that you are expecting and since the recommended way to catch is by reference, you should prefer:
catch (std::bad_cast const& ex)
Further reading: dynamic_cast conversion on cppreference.com.
I just dealt with the same error, but in my case I was going from a pointer to a pointer, so the other answers here did not apply. My error message was slightly different, however: error: cannot dynamic_cast 'f()' (of type 'class B*') to type 'class A*' (target is not pointer or reference to complete type).
The root cause in my case was much more simple and mundane.
Notice the addition of to complete type at the end. This caused me to remember that I did not include the header file for my class which I was using. It was not an unknown symbol because A* was forward declared with class A; in the header file, causing it to exist but not be complete, hence the error.
The solution in my case was to include the header file for the class I was casting to.
This is not the question asker's problem above, but as can be seen by my case can generate the same type of error.
Related
From C++17 standard (draft), 18.3.1:
[...] The exception-declaration shall not denote a pointer or reference to an incomplete type [...]
What is the reasoning behind disallowing catching incomplete types by reference?
If a function parameter is passed by reference, the complete type is only needed if the function actually accesses the object received, but it could just happily pass on the argument to another function without knowing anything about the type.
I cannot see why this should be different with exceptions - the exception data itself might reside anywhere appropriate, and on the (unwinded up to the handler) stack we find a reference to. Fine. If the handler now can drag sufficient information just from the type of the exception, why should it need to be aware of the complete definition?
So what did I miss?
struct Alice;
struct Bob;
int main() {
try {
throwAlice(); // extern
} catch (Bob&) {
return 0;
}
return 1;
}
What does the following program returns? 0 or 1 or nasal demons? Well, it depends on Alice inheriting from Bob.
To handle the exception catching mechanism, the compiler must have that information at compile-time. Bob should be a complete type.
The reason why is explain in:
[except.handle]/15
The variable declared by the exception-declaration, of type cv T or cv T& [YSC: here, cv T& = Bob&], is initialized from the exception object, of type E [YSC: here, E = Alice], as follows:
if T is a base class of E, the variable is copy-initialized from the corresponding base class subobject of the exception object;
otherwise, the variable is copy-initialized from the exception object.
which confirms the compiler need to know if Bob inherits from Alice at compile-time: Bob must be a complete type.
Based on VTT's comment to the question (unfortuntely deleted in the meanwhile, "exception handling relying on RTTI") and essential thoughts derived from YSC's answer:
Exceptions are thrown at run-time, the exception object is placed at some (in this scope unknwon, but) well defined location.
If now getting to catch the exception, we need to determine at run-time as well, if any of the exception handlers is a match for the exception currently thrown, i. e. some code like this:
try { throw e; }
catch(E1&) { /*...*/ }
catch(E2&) { /*...*/ }
catch(E3&) { /*...*/ }
Must result "somehwere" in code like this:
if(e instanceof(E1)) { /*...*/ }
else if(e instanceof(E2)) { /*...*/ }
else if(e instanceof(E3)) { /*...*/ }
with some appropriate instanceof definition (the term stolen from Java...). Such a definition now needs to compare if the RTTI of E<x> matches the RTTI of e or the one of any of e's base classes; naturally, for such comparison E<x>'s RTTI must be available at compile-time and thus the complete definition of E<x>.
Side note: If now RTTI contains base classes' RTTI in some kind of generic list, it is not even necessary any more to know at compile-time the exact type of the exception thrown.
I was reading about dynamic_cast and then I encountered the following statement (from cplusplus.com):
Compatibility note: This type of dynamic_cast requires Run-Time Type
Information (RTTI) to keep track of dynamic types. Some compilers
support this feature as an option which is disabled by default. This
needs to be enabled for runtime type checking using dynamic_cast to
work properly with these types.
After the example:
// dynamic_cast
#include <iostream>
#include <exception>
using namespace std;
class Base { virtual void dummy() {} };
class Derived: public Base { int a; };
int main () {
try {
Base * pba = new Derived;
Base * pbb = new Base;
Derived * pd;
pd = dynamic_cast<Derived*>(pba);
if (pd==0) cout << "Null pointer on first type-cast.\n";
pd = dynamic_cast<Derived*>(pbb);
if (pd==0) cout << "Null pointer on second type-cast.\n";
} catch (exception& e) {cout << "Exception: " << e.what();}
return 0;
}
What does the author mean by "this type of dynamic_cast"? Isn't dynamic_cast only used for polymorphic classes(almost)? And he mentions this RTTI as something that is needed for the dynamic cast to work, does that mean that you have to use dynamic_cast with caution because you do not know if it is supported fully by the compiler and therefore makes it riskier than the other casting operators which do not need this RTTI?
The compatibility note relates to the immediately preceding paragraph (and code example):
But dynamic_cast can also downcast (convert from pointer-to-base to pointer-to-derived) polymorphic classes (those with virtual members) if -and only if- the pointed object is a valid complete object of the target type.
And it's true: downcasting requires an object of polymorphic type, and RTTI to traverse the object's inheritance tree at runtime.
The other type of dynamic_cast is explained in the paragraph before that:
This naturally includes pointer upcast (converting from pointer-to-derived to pointer-to-base), in the same way as allowed as an implicit conversion.
No RTTI is required here as an object's base(s) is/are always known statically.
So you only need to fully read the surrounding text in order to understand the context of the words you're reading.
I would note, however, that in my experience a compiler with RTTI disabled by default is basically unheard of. I'm not saying that none exist — there may be some niche, industry-specific compilers targeting embedded platforms that do this to save the programmer a few bytes in their Makefile. But the compilers that most people use (GCC, Clang, Visual Studio, ICC, Comeau) all, to the best of my knowledge, pack RTTI as standard and leave it on until you ask for it to be turned off.
The author in the section mentioned by you referred to the cases when you are using dynamic_cast with polymorphic types: to be a little bit more precise, when you write something like dynamic_cast<X*>(p).
In cases like that, you are going to need Run-Time Type Information so that dynamic_cast can be used at all (see the example below).
You can make the compiler disable the generation of such information about every class with virtual functions by using the mentioned compiler option, -fno-rtti, but it's rarely recommended.
"Other" cases are about the usage of dynamic_cast for void*s.
For example, consider the following code:
class A {
public:
virtual ~A() = default;
};
class B : public A {};
int main()
{
A *p = new B();
void *pv = dynamic_cast<void*>(p);
//B *pb = dynamic_cast<B*>(p);
delete p;
return 0;
}
If you compile the code with g++ test.cpp -std=c++11 -fno-rtti, it's gonna be just fine. But, if you do the same after uncommenting B *pb = dynamic_cast<B*>(p);, the compiler is going to give the following error message for this specific line: error: ‘dynamic_cast’ not permitted with -fno-rtti. Note that the cast to void* works even if using -fno-rtti (which has been set either manually or by default).
rtti is expensive at runtime and some embedded systems compile with flags, disabling it. All it gives you are dynamic_cast and typeid.
Therefore, I interpret
because you do not know if it is supported fully by the compiler
as
because your code could have been compiled with rtti disabled.
I was playing with c++ exceptions and I've tried throwing an anonymous exception like this:
throw class : public std::exception
{
virtual const char *what() const noexcept
{
return "Custom exception";
}
} ex;
However I'm getting the following error when trying to compile:
error: expected primary-expression before ‘class’
throw class : public std::exception
^
My compiler is gcc 5.2.1 on Linux x86_64.
How can I achieve the desired result?
This is not an answer per-se, but some important information what will help you going forward:
First, throwing an anonymous exception is unlikely to be useful. Exceptions are caught by their type. If you can't name the type, you can't catch the exception explicitly - only by its base, in which case you may as well have just thrown the base.
Second (and this is important):
There's rarely a good reason to derive from std::exception directly. You should derive from one of the exception types defined in <stdexcept>
these are:
std::runtime_error - indicating that some runtime condition makes it impossible to perform the service at the moment (such as a missing file).
std::logic_error - indicating that what was attempted will never be possible and the program is fundamentally in error in a way that could not be detected at compile time.
Handy reference here:
http://en.cppreference.com/w/cpp/header/stdexcept
You can't declare a class in a throw statement. Declare the class first (anonymously if you like, naming it via a typedef), then you can throw it.
Better is to name the exception class, but put it in the nameless namespace:
namespace {
class LocalException : public std::exception {
const char *what() const noexcept override {
return "Custom exception";
}
};
}
....
throw LocalException();
or, if you insist, you can create an object of anonymous class, and throw that.
static class : public std::exception {
const char *what() const noexcept override {
return "Custom exception";
}
} LocalExceptionObject;
....
throw LocalExceptionObject;
Edit If you create a typedef, somebody can copy it, and it names the same class. You have to create an object of the anonymous class, and then nobody can name it.
Having said that, I don't think having anonymous things is useful. Far better to declare the class in a nameless namespace (so you know it is private), and just use it.
C++
I want a class to throw an exception before its constructor's body's opening curly brace { by using its own member function to prevent construction. I defined a member function, whose purpose is only to unconditionally throw an exception, with an arbitrarily chosen non-void return type and a dummy data member whose type matches that return type, so that I can trigger the throw by constructing this data member with a call to said member function in the constructor initializer list. This works but isn’t elegant because in a non-toy class, the dummy variable would serve no other purpose but to have an excuse for the member function to run, and the member function’s non-void return type serves no other purpose but to have an excuse for it to be callable by the constructor of the dummy data member of the same type.
This toy compiles but isn’t elegant:
class Toy
{
public:
Toy() : dummy(preventer()) {}
private:
int dummy;
int preventer() {throw -1; return 0;}
};
#include <iostream>
int main()
{
try
{
Toy t;
}
catch (const int& e)
{
std::cout << "caught the exception\n";
}
return 0;
}
Console Output:
caught the exception
Without the dummy variable, is there a way to throw an exception before the opening curly brace { of the constructor body?
Yes you can use a base class instead of a data member, and then invoking the base class' constructor.
Note that old versions of the GNU debugger gdb (some years ago) was unable to break on such exception.
However, works OK with Visual C++, and I believe also with modern versions of the GNU toolchain.
You can avoid the dummy return value of the function like this:
bool called = (function(), true);
The comma-operator in between the two expressions on the right evaluates the expressions in turn, discarding all but the last's result. What I'm wondering though is why you insist on doing that before the opening curly braces. What exactly are you trying to achieve here that you can't achieve with a call to the function as first thing in the body?
Note that if you want to abort as early as possible, doing that in a separate baseclass (you can use private inheritance there) is probably the best solution. It's the only solution that allows you to prevent even the construction of other bases, which your solution doesn't.
I'm curious to know what happens when compiling code with a dynamic cast whith RTTI disabled
(either with -fno-rttion GCC or with /GR- on visual studio). Does the compiler "falls back" to static_cast ? Since (at least on VS) it does only issue a warning, what will the compiled code do ?
More specifically, what bad things could happen if I compile without RTTI a code where I'm sure that there are no error possible with dynamic_cast (i.e. where dynamic_cast could be safely replaced by a static_cast) like this one :
class A{ /*...*/ } ;
class B : public A {
int foo() { return 42 ;}
} ;
//...
A * myA = new B() ;
int bar = (dynamic_cast<B*>(myA))->foo() ;
Reading the standard, in 5.2.7/6 we find that unless the target is an unambiguous base of the source, source must be a polymorphic type. Then in 10.3/1
Virtual functions support dynamic binding and objectoriented
programming. A class that declares or inherits a virtual function is
called a polymorphic class.
In other words the standard doesn't seem to say anything about your question. In this case, the standard doesn't allow for a compiler to turn off RTTI so for each compiler you need to check its documentation to see what would happen. Based on this reading, I think this is a compiler question, not a C++ language question as the tag indicates.
Alternately you can avoid the problem completely by just using static_cast when you know it's sufficient.
In MSVC, if your code is not compiled with RTTI enabled, a __non_rtti_object exception will be thrown, if the cast cannot be performed without a run-time check.
The easiest way to find out is to try it.
What you will find is that some of your dynamic casts will be flagged as illegal. Some won't. For example, the conversion is known at compile time when you use dynamic cast to upcast to an unambiguous base class.
Addendum
Re "Since (at least on VS) it does only issue a warning ..."
Ignore warnings at your peril. The best thing to do is to ensure that your code compiles without warnings, with warning levels set very high (and possibly converted to errors). Second best is to look at each and every warning you get and ensure that nothing untoward happens. In this case, something untoward will happen. You really should not care how that untoward event is implemented. What you should care about is getting rid of it.
Just try it:
#include <iostream>
#include <typeinfo>
#include <typeindex>
#include <memory>
#include <vector>
#include <array>
#include <string>
class Base {
public:
virtual ~Base() {
}
};
class A: public Base {
};
class B: public Base {
};
using namespace std;
int main() {
A *a = new A;
auto *ptr = dynamic_cast<B*>(a);
if (!ptr)
std::cout << "failed to cast" << std::endl;
return 0;
}
Without -fno-rtti, the program compiles and the output is:
failed to cast
With -fno-rtti, the program failed to compile:
main.cpp:25:35: error: ‘dynamic_cast’ not permitted with -fno-rtti
auto* ptr = dynamic_cast<B*>(a);
^
You can also test this online here: https://onlinegdb.com/pYTQu2ne2