19.8.1. static_cast and const_cast

[ fromfile: types.xml id: staticcast ]

static_cast<DestType>(expr) converts the value expr to type DestType, provided that the compiler knows of an implicit conversion from expr to DestType. All type-checking is done at compile time.

        static_cast<char>('A' + 1.0);
        static_cast<double>(static_cast<int>(y) + 1);
   

The static_cast operator converts between related types such as one pointer type to another, an enumeration type to an integral type, or a floating-point type to an integral type. These conversions are well defined, portable, and invertible. The compiler can apply some minimal type checking for each static_cast.

static_cast cannot cast away constness. For that you must use const_cast<DestType>(expr), which creates a non-const version of expr.

In that case, the DestType can differ from the type of expr only in the presence or absence of const/volatile.

For an int i, static_cast<double>(i) creates a temporary of type double that has the value of i. The variable i itself is not changed by this cast. Example 19.10 contains both kinds of casts.

Example 19.10. src/ansicast/m2k.cpp

// Miles are converted to kilometers.
#include <QTextStream>

QTextStream cin(stdin);
QTextStream cout(stdout);
QTextStream cerr(stderr);

const double  m2k = 1.609;    // conversion constant

inline double mi2km(int miles) {
    return (miles * m2k);
}

int main() {
    int  miles;
    double kilometers;
    cout << "Enter distance in miles: " << flush;
    cin >> miles ;  
    kilometers = mi2km(miles);
    cout << "This is approximately "
         <<  static_cast<int>(kilometers)
         << "km."<< endl;
    cout << "Without the cast, kilometers = "
         << kilometers << endl;
    double* dp = const_cast<double*>(&m2k); 
    cout << "m2k: " << m2k << endl;
    cout << "&m2k: " << &m2k << "  dp: " << dp << endl;
    cout << "*dp: " << *dp << endl;
    *dp = 1.892;  1
    cout << "Can we reach this statement? " << endl;
    return 0;
}

Output:

Enter distance in miles: 23
This is approximately 37km.
Without the cast, kilometers = 37.007
m2k: 1.609
&m2k: 0x8049048  dp: 0x8049048
*dp: 1.609
Segmentation fault



1

What are we attempting to do here?


Here are some observations regarding the previous example.

Casting away const

In general, const_cast is used only on const-references and pointers to non-const objects. Using const_cast to change const objects has undefined behavior because const objects may be stored in read-only memory (which the operating system protects). In the case of const int, trying to change it by casting away const depends on compiler optimization techniques, which frequently optimize them out of existance (by doing precompilation value replacement). Example 19.11 gives some indication of the strange behavior that can occur.

Example 19.11. src/casts/constcast1.cpp

#include <iostream>
using namespace std;

int main() {
    const int N = 22;
    int* pN = const_cast<int*>(&N);
    *pN = 33;
    cout << N << '\t' << &N << endl;
    cout << *pN << '\t' << pN << endl;
}
Output:

22      0xbf91cfa0
33      0xbf91cfa0 

The preceding output, obtained with gcc version 4.4.3, might be different on your system because the behavior is undefined.

In this example, we used const_cast to obtain a regular pointer to a const int. Because the const int is in stack storage class, attempting to change its memory does not cause a segmentation fault. The compiler is unable to "optimize out" the int, and the const_cast tells it not to even try.