I honestly can't understand why anybody recommends them over C-style casting.
Then you should consider that they were invented because people got tired of shooting themselves in the foot by “over-casting”.
L. Spiro
I honestly can't understand why anybody recommends them over C-style casting.
Then you should consider that they were invented because people got tired of shooting themselves in the foot by “over-casting”.
L. Spiro
I honestly can't understand why anybody recommends them over C-style casting.Then you should consider that they were invented because people got tired of shooting themselves in the foot by “over-casting”.
L. Spiro
static_cast<T> == (T)
reinterpret_cast<T*> == (T*)
const_cast<const T*> == (T*)
I've not once run into a bug caused by C style casting that would not also have been caused by one of those C++ casts. So instead of just shooting yourself in the foot, you should get three guns to choose from?
It was a sobering realisation that even floating point limits can be easily exceeded by multiplying seemingly small quantities, especially since they are used in the oft-mentioned "critical loops", "engine cores," "numeric libraries." I started appreciating things like media compression artifacts, 3D graphics clipping, statistical / mechanical errors...
Most of the time in games you're working with values -1.0 <= x <= 1, and multiplying values in that range together. This prevents the issue you noticed from happening because the result will always be in that same range. The higher precision of double might make some difference in some corner case, but generally it's not necessary. I personally have had good results in software rasterizing with a fixed point type with 15 bits of precision (8 bits less than IEEE single precision float).
I just had this naive impression that ieee float dealt with the int-overflowing-multiply-by-10 by incrementing an exponent such that it could handle much larger values; e.g. 10 to the 10 "felt" possible with little error. On the fraction part, I "knew" shifting the decimal point would favour double but a clear "error" in the fraction part when doing float(double) was a shock.
floating point exponents are applied to a base of 2, not 10, unless you specify them as decimal.
IIRC 2^127x(1-FLT_EPSILON) is the largest value possible in a float, but you'd need 128 bits to represent all numbers in this range accurately.
static_cast<T*> == (T)
reinterpret_cast<T*> == (T*)
const_cast<T*> == (const T*)
I've not once run into a bug caused by C style casting that would not also have been caused by one of those C++ casts. So instead of just shooting yourself in the foot, you should get three guns to choose from?
Just a minor complaint about your usage of const cast - const_cast<const T*> is wrong, the way you use it is actually const_cast<T*>, and thus the equivalent c-style cast is (T*) - thats one of the reasons why C-style casts can be considered bad, because you might just cast a const modifier away where you didn't expect to.
I've heard of a studio in the past few years ban C++ casts altogether due to bugs/weirdness in generated assembly.
As for "getting the wrong type of cast" with a C-style cast, you can look at the code and easily find the different between reinterpret and static cast by noticing if the cast is casting a pointer type or not. As for const cast, well that only holds merit if your code base believes in using const in the first place. I think the argument that made the most sense to me is C++ casts are way easier to parse compared to C-style casts, which makes code pre-processing potentially easier.
static_cast<T*> == (T)
reinterpret_cast<T*> == (T*)
const_cast<T*> == (const T*)
I've not once run into a bug caused by C style casting that would not also have been caused by one of those C++ casts. So instead of just shooting yourself in the foot, you should get three guns to choose from?Just a minor complaint about your usage of const cast - const_cast<const T*> is wrong, the way you use it is actually const_cast<T*>, and thus the equivalent c-style cast is (T*) - thats one of the reasons why C-style casts can be considered bad, because you might just cast a const modifier away where you didn't expect to.
You're right, of course, I was typing that message in a hurry because I was on my way out the door.
I've heard of a studio in the past few years ban C++ casts altogether due to bugs/weirdness in generated assembly.
As for const cast, well that only holds merit if your code base believes in using const in the first place.
I think the argument that made the most sense to me is C++ casts are way easier to parse compared to C-style casts, which makes code pre-processing potentially easier.
As for "getting the wrong type of cast" with a C-style cast, you can look at the code and easily find the different between reinterpret and static cast by noticing if the cast is casting a pointer type or not.
I can believe weirdness, but not bugs, unless it was some special-purpose compiler they were using (IE one for some specific console).
I think const serves a valid purpose in describing the usage of function arguments. Const allows optimization in some handful of cases, too. I'm not sure it's valid for much else.
So we should never use C-style casts... to shave a few microseconds off compile time?
This is not an accurate depiction of the casts.static_cast == (T)
reinterpret_cast == (T*)
const_cast == (const T*)
#include <iostream>
class AbstractEntity
{
public:
virtual void Print() { std::cout << "AbstractEntityA" << std::endl; }
};
class DerivedA : public AbstractEntity
{
public:
void Print() { std::cout << "DerivedA" << std::endl; }
};
class DerivedB
{
public:
void Print() { std::cout << "DerivedB" << std::endl; }
};
int main()
{
AbstractEntity *entityA = (AbstractEntity*)new DerivedA();
AbstractEntity *entityB = (AbstractEntity*)new DerivedB();
DerivedA *derivedA = (DerivedA*)entityB;
DerivedB *derivedB = (DerivedB*)entityA;
derivedA->Print();
derivedB->Print();
return 0;
}
This code compiles fine