Namespaces
Variants
Views
Actions

cv (const-volatility) specifiers and qualifiers

From cppreference.com
< cpp‎ | language
Revision as of 07:44, 11 March 2014 by Cubbi (Talk | contribs)

Appear in any type specifier, including decl-specifier-seq of declaration grammar, to specify constness or volatility of the type being declared.

  • const - defines that the type is constant.
  • volatile - defines that the type is volatile.
  • mutable - defines that a member of a class does not affect the externally visible state of the class. mutable members can be modified in constant classes, that is constness is essentially ignored for the particular member.

Contents

Explanation

For any type T (including incomplete types), other than function type or reference type, there are three more distinct types in the C++ type system: const-qualified T, volatile-qualified T, and const-volatile-qualified T.

Note: cv-qualifiers and cv-specifiers are not the same thing: cv-qualifiers are the properties of a type whereas cv-specifiers are the language keywords used to define cv-qualifiers.

When an object is declared, the cv-specifiers used in the declarations determine the constness or volatility of the object, as follows:

  • const object - an object whose type is const-qualified, or a non-mutable subobject of a const object. Such object cannot be modified: attempt to do so directly is a compile-time error, and attempt to do so indirectly (e.g., by modifying the const object through a reference or pointer to non-const type) results in undefined behavior.
  • volatile object - an object whose type is volatile-qualified, or a subobject of a volatile object, or a mutable subobject of a const-volatile object. Every access (read or write operation, member function call, etc.) on the volatile object is treated as a visible side-effect for the purposes of optimization (that is, within a single thread of execution, volatile accesses cannot be reordered or optimized out. This makes volatile objects suitable for communication with a signal handler, but not with another thread of execution, see std::memory_order)
  • const volatile object - an object whose type is const-volatile-qualified, a non-mutable subobject of a const volatile object, a const subobject of a volatile object, or a non-mutable volatile subobject of a const object. Behaves as both a const object and as a volatile object.

There is partial ordering of cv-qualifiers by the order of increasing restrictions. The type can be said more or less cv-qualified then:

  • unqualified < const
  • unqualified < volatile
  • unqualified < const volatile
  • const < const volatile
  • volatile < const volatile

References and pointers to cv-qualified types may be implicitly converted to references and pointers to more cv-qualified types. In particular, the following conversions are allowed:

  • unqualified type can be converted to const
  • unqualified type can be converted to volatile
  • unqualified type can be converted to const volatile
  • const type can be converted to const volatile
  • volatile type can be converted to const volatile
Note: additional restrictions are imposed on multi-level pointers.

To convert a reference or a pointer to a cv-qualified type to a reference or pointer to a less cv-qualified type, const_cast must be used.

cv-qualifiers and array types

Applying cv-qualifiers to any array type affects its element type, rather than the array type itself.

using A = int[10];
using B = volatile int;
volatile A a;
         B b[10]; //a and b have the same type (array of 10 volatile int)

Keywords

const, volatile, mutable

Example

int main()
{
    int n1 = 0;           // non-const object
    const int n2 = 0;     // const object
    int const n3 = 0;     // const object (same as n2)
    volatile int n4 = 0;  // volatile object
    const struct X {
        int n1;
        mutable int n2;
    } x = {0, 0};      // const object with mutable member
 
    n1 = 1; // ok, modifiable obejct
//  n2 = 2; // error: non-modifiable object
    n4 = 3; // ok, treated as a side-effect.
//  x.n1 = 4; // error: member of a const object is const
    x.n2 = 4; // ok, mutable member of a const object isn't const
 
    const int& r1 = n1; // reference to const bound to non-const object
//  r1 = 2; // error: attempt to modify through reference to const
    const_cast<int&>(r1) = 2; // ok, modifies n1
 
    const int& r2 = n2; // reference to const bound to const object
//  r2 = 2; // error: attempt to modify through reference to const
//  const_cast<int&>(r2) = 2; // undefined behavior: attempt to modify const object
}

Output:

# typical machine code produced on an x86_64 platform
# (only the code that contributes to observable side-effects is emitted)
main:
    movl    $0, -4(%rsp) # volatile int n4 = 0;
    movl    $3, -4(%rsp) # n4 = 3;
    xorl    %eax, %eax   # return 0 (implicit)
    ret