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.
Related
class A
{
public:
void display()
{
cout << "class A\n";
}
};
class B
{
public:
void show()
{
cout << "class B\n";
}
};
int main()
{
A* aPtr = new A;
B* bPtr = new B;
B* bPtr2 = (B*) aPtr;
return 0;
}
In the above code why in C++ it is allowed to cast a pointer of one class type to another. Since the two class are not related still why B* bPtr2 = (B*) aPtr; not throws an compile time error for casting the pointers of unrelated types.
The C cast syntax will do different things depending on the types involved. One of the things it can do is a reinterpret_cast.
This is one of the reasons you should not use the C cast syntax, and instead stick with C++ casts. With C++ casts you get the operation you asked for instead of possibly something else.
a c++ compiler should not allow this and should throw an compile time error.
C compatibility is one of the reasons C++ has been successful. C shouldn't have had this 'polymorphic' cast syntax, but it did and C++ needed to be compatible. If you're writing new C++ code you should simply not use the old syntax.
On some compilers you can disable C style casts using something like: -Werror=old-style-cast.
The example you show is called an "unsafe" or "unchecked" cast, and quite rightly so. It is a low-level construct carried over from backward compatibility with C. You should not be using this in modern C++ code.
The proper way to do a cast is to use the operations static_cast, dynamic_cast or their relatives. See the related question When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used? for more details.
You can force GCC to show a warning for these casts by using the option -Wold-style-cast. To convert all warning into errors, you can add the option -Werror.
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
Let's say I have these types:
struct A {
int a;
};
struct B {
int b;
};
struct C : public A, public B {
int c;
};
A C* pointer can be cast to A* pointer without adjusting the actual address at all. But when C* is cast to B*, the value must change. I'd like to ensure that two related types I have can be cast to each other without a change in address (i.e. that there is no multiple inheritance, or that the base class is the first base of the derived class). This could be checked at run-time, e.g. like so
assert(size_t(static_cast<A*>((C*)0xF000) == 0xF000);
assert(size_t(static_cast<B*>((C*)0xF000) != 0xF000);
That works. But this information is known at compile time, so I'm looking for a way to do a compile-time assert on it. The obvious ways of converting the above to a static assert (e.g. replace assert with BOOST_STATIC_ASSERT give the error "a cast to a type other than an integral or enumeration type cannot appear in a constant-expression" with g++ 4.2.
Portability isn't too important. Using gcc extensions, or hacky template tricks would all be fine.
Update: Found that almost the same question has been asked before: C++, statically detect base classes with differing addresses?. Using offsetof() is the only useful suggestion there too.
"I'd like to ensure that two related types can be cast to each other without a change in address (i.e. that there is no multiple inheritance, or that the base class is the first base of the derived class)."
Your "i.e." isn't correct. For instance, it's entirely possible that the first 4 bytes of Derived are a vtable pointer, even when Base isn't polymorphic. Yes, C++ compilers are easier if (1) the first base subobject is at offset 0, and (2) the vtable pointer is at offset 0. But those two goals are inherently at odds, and there is no clear better choice.
Now, the first part could be tested in theory. With standard-layout types, there would be no difference in offset_of(Base, first_member) and offset_of(Derived, first_member). But in practice, offset_of doesn't work for interesting types; it's UB. And the whole point of this check is to check a type, so it should fail reliably for nonstandard-layout types.
Based on a suggestion from MSalters, and an answer from C++, statically detect base classes with differing addresses?, here is the closest thing to an answer I can come up with. It's probably gcc-specific, and requires knowing some member of the base class:
#pragma GCC diagnostic ignored "-Winvalid-offsetof" // To suppress warning.
BOOST_STATIC_ASSERT(offsetof(C, a) == offsetof(A, a));
BOOST_STATIC_ASSERT(offsetof(C, b) != offsetof(B, b));
#pragma GCC diagnostic warn "-Winvalid-offsetof"
Obviously this is both inconvenient and scary (requires to know a member and to turn off a warning).
Am I right in assuming that C-style casts (which are discouraged) are nothing but reinterpret_casts? Using the latter is visually striking and easy to search when looking for nasty casts, and hence it's recommended over C-style casts?
If casting away const using const_cast and writing to a originally const object is undefined, what is the purpose of const_cast?
Note: I know that Bjarne rightly condemns casting operations that they are unsafe and even goes to the extent of stating "An ugly operation should have an ugly syntactic form." and hence the verbosity of casting operators in C++. So I'll try to minimize their usage. Promise. :)
No. A C cast can do the equivalent of a const_cast, a static_cast, a reinterpret_cast, or a combination thereof. In case that wasn't quite enough, it can also do at least one minor trick that no combination of the newer casts can do at all!
You can use const_cast with defined results if the original variable is defined without const, but all you have is a const pointer or reference to that object. OTOH, if you think you have a good reason to use a const_cast, chances are that you should really look up mutable instead.
Edit: I suppose I should have said it right off, but a C-style cast can convert to an an inaccessible base class. For example, consider something like:
[Edit: I'm updating the code to something that'll compile and (usually) demonstrate problem. ]
#include <iostream>
class base1 {
public:
virtual void print() { std::cout << "base 1\n"; }
};
class base2 {
public:
virtual void print() { std::cout << "base 2\n"; }
};
class derived : base1, base2 {}; // note: private inheritance
int main() {
derived *d = new derived;
base1 *b1 = (base1 *)d; // allowed
b1->print(); // prints "base 1"
base2 *b2 = (base2 *)d; // also allowed
b2->print(); // prints "base 2"
// base1 *bb1 = static_cast<base *>(d); // not allowed: base is inaccessible
// Using `reinterpret_cast` allows the code to compile.
// Unfortunately the result is different, and normally won't work.
base1 *bb2 = reinterpret_cast<base1 *>(d);
bb2->print(); // may cause nasal demons.
base2 *bb3 = reinterpret_cast<base2 *>(d);
bb3->print(); // likewise
return 0;
}
The code using the reinterpret_casts will compile -- but attempting to use the result (of at lest one of the two) will cause a major problem. The reinterpret_cast takes the base address of the derived object and attempts to treat it as if it was the specified type of base object -- and since (at most) one base object can actually exist at that address, trying to treat it as the other can/will cause major problems. Edit: In this case, the classes are essentially identical except for what they print, so although anything could happen, with most compilers, both of the last two will print out "base 1". The reinterpret_cast takes whatever happens to be at that address and tries to use it as the specified type. In this case, I've (tried to) make that do something harmless but visible. In real code, the result probably won't be so pretty.
The C-style cast will work like a static_cast would if the code had used public inheritance instead of private -- i.e. it's aware of where in the derived class each base class object "lives", and adjusts the result, so each resulting pointer will work because it's been adjusted to point at the right place.
No, C-style casts can act as reinterpret_casts, const-casts or static_casts depending on the situation. This is why they are discouraged - you see a C-style cast in code and need to look for details to see what it will do. For example:
const char* source;
int* target = (int*)source;// - acts as const_cast and reinterpret_cast at once
//int* target = retinterpret_cast<int*>source;// - won't compile - can't remove const
Remember, that a const cast may be acting on something other then the original identifier:
void doit(const std::string &cs)
{
std::string &ms = const_cast<std::string &>(cs);
}
int main()
{
std::string s;
doit(s);
}
So while doit is casting away const, in this example the underlying string is not const so no undefined behavior.
Update
Okay, here's a better example of when using const_cast is not completely worthless. We start with a base class with a virtual function that takes a const parameter:
class base
{
public:
virtual void doit(const std::string &str);
};
and now you want to override that virtual function.
class child : public base
{
public:
virtual void doit(const std::string &str)
{
std::string &mstr = const_cast<std::string &>(str);
}
};
Because of the logic/structure of your code, you know that child::doit will only be called with non-const strings (and class base is not under your control so you can't modify it nor can you change the signature of child::doit because then it will not longer override base::doit). In this case, it's safe to cast away const.
Yes, this is risky. Perhaps when you write that, it's true that the execution will never reach child::doit with a non-const string and the code is valid. But that could change either while maintaining your program or perhaps when you rebuild and pick up the latest version of class base.
const_cast is used to remove const from a type. It also can remove volatile. If the object really is const then the result cannot be written to and still be well-defined behavior. If, however, it is promoted to const (by being passed into a const T function, then const_casting it back to non-const is ok. ( i found some more info here)
reinterpret_cast cannot remove const or volatile from a type.
see also
C-style casts are really the sledge hammer of programming - you basically tell the compiler that the square peg over there will fit through this round hole no matter what. In that sense, reinterpret_cast is very similar.
The main advantage I see in using the C++-style cast operators are that they allow you to express your intent better and allow the compiler to still to some checking on the operation you're asking it to perform rather than the one-size-fits-all style C cast.
Regarding const_cast- you often get into the situation where you are passing an object around via const reference simply because the API requires you to do this. Say, you've got function X that tasks a C-style string:
void X(const char *str) { ... }
Inside that function you're passing the parameter to a C function that expects a char *, even though it's not changing the string. The only way to accommodate this would be to const_cast str.
I'd be very careful using any sort of cast, often this shows that there is something not quite right with your design but sometimes you have to convince the compiler that the peg it's looking at isn't as square as it assumes. Only then should you use the cast operators.
I saw one book on C++ mentioning that navigating inheritance hierarchies using static cast is more efficient than using dynamic cast.
Example:
#include <iostream>
#include <typeinfo>
using namespace std;
class Shape { public: virtual ~Shape() {}; };
class Circle : public Shape {};
class Square : public Shape {};
class Other {};
int main() {
Circle c;
Shape* s = &c; // Upcast: normal and OK
// More explicit but unnecessary:
s = static_cast<Shape*>(&c);
// (Since upcasting is such a safe and common
// operation, the cast becomes cluttering)
Circle* cp = 0;
Square* sp = 0;
// Static Navigation of class hierarchies
// requires extra type information:
if(typeid(s) == typeid(cp)) // C++ RTTI
cp = static_cast<Circle*>(s);
if(typeid(s) == typeid(sp))
sp = static_cast<Square*>(s);
if(cp != 0)
cout << "It's a circle!" << endl;
if(sp != 0)
cout << "It's a square!" << endl;
// Static navigation is ONLY an efficiency hack;
// dynamic_cast is always safer. However:
// Other* op = static_cast<Other*>(s);
// Conveniently gives an error message, while
Other* op2 = (Other*)s;
// does not
} ///:~
However, both dynamic cast and static cast (as implemented above) need RTTI enabled for such navigation to work. It's just that dynamic cast requires the class hierarchy to be polymorphic (i.e. base class having at least one virtual function).
Where does this efficiency gain for static cast come from?
The book does mention that dynamic cast is the preferred way for doing type-safe downcasting.
static_cast per se DOESN'T need RTTI -- typeid does (as does dynamic_cast), but that's a completely different issue. Most casts are just telling the compiler "trust me, I know what I'm doing" -- dynamic_cast is the exception, it asks the compiler to check at runtime and possibly fail. That's the big performance difference right there!
It's much better to avoid switching on types at all if possible. This is usually done by moving the relevant code to a virtual method that is implemented differently for different subtypes:
class Shape {
public:
virtual ~Shape() {};
virtual void announce() = 0; // And likewise redeclare in Circle and Square.
};
void Circle::announce() {
cout << "It's a circle!" << endl;
}
void Square::announce() {
cout << "It's a square!" << endl;
}
// Later...
s->announce();
If you are working with a pre-existing inheritance hierarchy that you can't change, investigate the Visitor pattern for a more extensible alternative to type-switching.
More info: static_cast does not require RTTI, but a downcast using it can be unsafe, leading to undefined behaviour (e.g. crashing). dynamic_cast is safe but slow, because it checks (and therefore requires) RTTI info. The old C-style cast is even more unsafe than static_cast because it will quietly cast across completely unrelated types, where static_cast would object with a compile-time error.
With the static cast (and typeid check) you cannot downcast to an intermediate type (child derives from father derives from grandfather, you cannot downcast from grandfather to father) the usage is a little more limited. static_cast without the typeid check is sacrificing correctness for perfomance, and then you know what they say:
He who sacrifices correctness for performance deserves neither
Then of course, there are situations where you are in desperate need of a few CPU instructions and there is nowhere else to look for improvements and you are actually safe on what you are doing and you have meassured (right?) that the only place to gain performance is using static_cast instead of dynamic_cast... then you know you must rework your design, or your algorithms or get better hardware.
The restrictions you impose by using rtti + static_cast is that you will not be able to extend your code with new derived classes at a later time without reworking all places where you have used this trick to gain just a few CPU instructions. That reworking itself will probably take more time (engineering time that is more expensive) than the CPU time you have obtained. If, at any rate, the time devoted to downcasts is noticeable, then rework your design as j_random_hacker suggests, it will improve both in design and performance.
dynamic_cast would return NULL if you hadn't done the typeid check and the cast couldn't succeed. static_cast would succeed (and lead to undefined behavior, such as an eventual crash). That's likely the speed difference.