Search code examples
c++pointersconstantsimplicit-conversionvolatile

Conversions between volatile, const, volatile const, and "neither" types


What does the C++(11) standard say about conversions among volatile, const, volatile const, and "neither" types? I understand that it's well-defined and acceptable to assign a const type to a non-const and non-volatile type, but what about conversions among the following types (where T is some type)?

// T
T
T volatile
T const 
T volatile const 

// Pointer-to-T
T*
T volatile*
T const*
T volatile const*

// Volatile pointer-to-T
T* volatile
T volatile* volatile
T const* volatile
T volatile const* volatile

// Const pointer-to-T
T* const
T volatile* const
T const* const
T volatile const* const

// Volatile const pointer-to-T
T* volatile const
T volatile* volatile const
T const* volatile const
T volatile const* volatile const

As a simple example, consider the following code:

T volatile a;
T const b;

a = b; // implicit conversion from const to volatile; okay?

template<typename T>
void fcn(T& t)
{
    t = b; // implicit conversion from const to non-const, which I assume is okay
}
fcn(a); // implicit conversion from volatile to non-volatile; okay?

Solution

  • What can you assign to what?

    You can always assign volatile values to non-const values. You can also assign const and non-const values to volatile values. You can never assign anything to const values, because they're const.

    Does a conversion occur?

    No - it's just doing an assignment.

    Why is this?

    volatile means that any accesses to an object cannot be optimized out. There are actually very few cases where volatile is ever needed, or used. These cases are:

    • When you're timing an operation, and don't want the calculation to be optimized out (Please use a benchmarking library for this. Don't roll your own)
    • When you're doing memory mapped IO. In this case, you want to guarantee that reads and writes aren't optimized out, so volatile can be used.

    Because of this, it must be possible to assign volatile to regular objects and vice versa. At the same time, however, volatile references shouldn't be implicitly converted to regular references, because that would potentially lead to reads and writes being optimized out.

    What about const?

    You can assign const stuff to anything, but nothing can be assigned to const (because it's const).