Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/language/cv"

From cppreference.com
< cpp‎ | language
m (See also: tt+nomono)
m ({{lc|mutable}} specifier: link in header does not work, change lc to tt in header)
 
(16 intermediate revisions by 7 users not shown)
Line 1: Line 1:
{{title|cv ({{small|const}} and {{small|volatile}}) type qualifiers}}
+
{{title|cv {{small|({{tt|const}} and {{tt|volatile}})}} type qualifiers}}
 
{{cpp/language/declarations/navbar}}
 
{{cpp/language/declarations/navbar}}
  
 
Appear in any type specifier, including {{spar|decl-specifier-seq}} of  {{rlp|declarations|declaration grammar}}, to specify constness or volatility of the object being declared or of the type being named.
 
Appear in any type specifier, including {{spar|decl-specifier-seq}} of  {{rlp|declarations|declaration grammar}}, to specify constness or volatility of the object being declared or of the type being named.
 
+
* {{c/core|const}} - defines that the type is ''constant''.
:*{{ttb|const}} - defines that the type is ''constant''.
+
* {{c/core|volatile}} - defines that the type is ''volatile''.
:*{{ttb|volatile}} - defines that the type is ''volatile''.
+
  
 
===Explanation===
 
===Explanation===
For any type {{tt|T}} (including incomplete types), other than {{rlp|functions|function type}} or {{rlp|reference|reference type}}, there are three more distinct types in the C++ type system: {{spar|const-qualified}} {{tt|T}}, {{spar|volatile-qualified}} {{tt|T}}, and {{spar|const-volatile-qualified}} {{tt|T}}.
+
Any (possibly {{rlp|type#Incomplete type|incomplete}}) type other than {{rlp|functions|function type}} or {{rlp|reference|reference type}} is a type in a group of the following four distinct but related types:
 +
* A ''cv-unqualified'' version.
 +
* A ''const-qualified'' version.
 +
* A ''volatile-qualified'' version.
 +
* A ''const-volatile-qualified'' version.
 +
 
 +
These four types in the same group have the same {{rlp|object#Object representation and value representation|representation}} and {{rlp|object#Alignment|alignment}} requirements.
  
:Note: {{rlp|array|array types}} are considered to have the same cv-qualification as their element types.
+
{{rlp|array|Array types}} are considered to have the same cv-qualification as their element types.
  
 +
====const and volatile objects====
 
When an object is first created, the cv-qualifiers used (which could be part of {{spar|decl-specifier-seq}} or part of a {{spar|declarator}} in a {{rlp|declarations|declaration}}, or part of {{spar|type-id}} in a {{rlp|new|new-expression}}) determine the constness or volatility of the object, as follows:
 
When an object is first created, the cv-qualifiers used (which could be part of {{spar|decl-specifier-seq}} or part of a {{spar|declarator}} in a {{rlp|declarations|declaration}}, or part of {{spar|type-id}} in a {{rlp|new|new-expression}}) determine the constness or volatility of the object, as follows:
  
*'''''const object''''' - an object whose type is {{spar|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.
+
* A ''const object'' is
*'''''volatile object''''' - an object whose type is {{spar|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.) made through a glvalue expression of volatile-qualified type<!--note; until p0612r0/NB comment CH2 on C++17, C++ standard said 'object', rather than 'expression', but this made it impossible to use volatile as intended--> is treated as a visible side-effect for the {{rlp|as_if|purposes of optimization}} (that is, within a single thread of execution, volatile accesses cannot be optimized out or reordered with another visible side effect that is {{rlp|eval order|sequenced-before}} or sequenced-after the volatile access. This makes volatile objects suitable for communication with a [[cpp/utility/program/signal|signal handler]], but not with another thread of execution, see {{lc|std::memory_order}}). Any attempt to refer to a volatile object through a {{rlp|value_category#glvalue|glvalue}} of non-volatile type (e.g. through a reference or pointer to non-volatile type) results in undefined behavior.
+
:* an object whose type is const-qualified, or
*'''''const volatile object''''' - an object whose type is {{spar|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.
+
:* a non-[[#mutable|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.
  
==={{lc|mutable}} specifier===
+
* A ''volatile object'' is
 +
:* an object whose type is volatile-qualified,
 +
:* a subobject of a volatile object, or
 +
:* a [[#mutable|mutable]] subobject of a const-volatile object.
 +
: Every access (read or write operation, member function call, etc.) made through a glvalue expression of volatile-qualified type<!--note; until p0612r0/NB comment CH2 on C++17, C++ standard said 'object', rather than 'expression', but this made it impossible to use volatile as intended--> is treated as a visible side-effect for the {{rlp|as if|purposes of optimization}} (that is, within a single thread of execution, volatile accesses cannot be optimized out or reordered with another visible side effect that is {{rlp|eval order|sequenced-before}} or sequenced-after the volatile access. This makes volatile objects suitable for communication with a [[cpp/utility/program/signal|signal handler]], but not with another thread of execution, see {{lc|std::memory_order}}). Any attempt to access a volatile object through a {{rlp|value category#glvalue|glvalue}} of non-volatile type (e.g. through a reference or pointer to non-volatile type) results in undefined behavior.
  
:*{{ttb|mutable}} - permits modification of the class member declared mutable even if the containing object is declared const.
+
* A ''const volatile object'' is
 +
:* an object whose type is const-volatile-qualified,
 +
:* a non-[[#mutable|mutable]] subobject of a const volatile object,
 +
:* a const subobject of a volatile object, or
 +
:* a non-[[#mutable|mutable]] volatile subobject of a const object.
 +
: Behaves as both a const object and as a volatile object.
 +
 
 +
Each cv-qualifier ({{c/core|const}} and {{c/core|volatile}}) can appear at most once in any cv-qualifier sequence. For example, {{c/core|const const}} and {{c/core|volatile const volatile}} are not valid cv-qualifier sequences.
 +
 
 +
{{anchor|mutable}}
 +
==={{tt|mutable}} specifier===
 +
* {{c/core|mutable}} - permits modification of the class member declared mutable even if the containing object is declared const (i.e., the class member is mutable).
  
 
May appear in the declaration of a non-static {{rlp|data members|class members}} of non-reference non-const type:
 
May appear in the declaration of a non-static {{rlp|data members|class members}} of non-reference non-const type:
 
{{source|
 
{{source|
class X {
+
class X
  mutable const int* p;         // OK
+
{
  mutable int* const q;         // ill-formed
+
    mutable const int* p; // OK
 +
    mutable int* const q; // ill-formed
 +
    mutable int&      r; // ill-formed
 
};
 
};
 
}}
 
}}
  
Mutable is used to specify that the member does not affect the externally visible state of the class (as often used for mutexes, memo caches, lazy evaluation, and access instrumentation).
+
{{c/core|mutable}} is used to specify that the member does not affect the externally visible state of the class (as often used for mutexes, memo caches, lazy evaluation, and access instrumentation).
  
 
{{source|1=
 
{{source|1=
class ThreadsafeCounter {
+
class ThreadsafeCounter
  mutable std::mutex m; // The "M&M rule": mutable and mutex go together
+
{
  int data = 0;
+
    mutable std::mutex m; // The "M&M rule": mutable and mutex go together
public:
+
    int data = 0;
  int get() const {
+
public:
     std::lock_guard<std::mutex> lk(m);
+
    int get() const
    return data;
+
     {
  }
+
        std::lock_guard<std::mutex> lk(m);
  void inc() {
+
        return data;
     std::lock_guard<std::mutex> lk(m);
+
    }
    ++data;
+
   
  }
+
    void inc()
 +
     {
 +
        std::lock_guard<std::mutex> lk(m);
 +
        ++data;
 +
    }
 
};
 
};
 
}}
 
}}
Line 50: Line 78:
 
===Conversions===
 
===Conversions===
 
There is partial ordering of cv-qualifiers by the order of increasing restrictions. The type can be said ''more'' or ''less'' cv-qualified than:
 
There is partial ordering of cv-qualifiers by the order of increasing restrictions. The type can be said ''more'' or ''less'' cv-qualified than:
 +
* ''unqualified'' < {{c/core|const}}
 +
* ''unqualified'' < {{c/core|volatile}}
 +
* ''unqualified'' < {{c/core|const volatile}}
 +
* {{c/core|const}} < {{c/core|const volatile}}
 +
* {{c/core|volatile}} < {{c/core|const volatile}}
  
:* ''unqualified'' < {{tt|const}}
+
References and pointers to cv-qualified types can be implicitly converted to references and pointers to more cv-qualified types, see {{rlp|implicit cast#Qualification conversions|qualification conversions}} for details.
:* ''unqualified'' < {{tt|volatile}}
+
:* ''unqualified'' < {{tt|const volatile}}
+
:* {{tt|const}} < {{tt|const volatile}}
+
:* {{tt|volatile}} < {{tt|const volatile}}
+
  
References and pointers to cv-qualified types may be {{rlp|implicit_cast#Qualification_conversions | implicitly converted}} to references and pointers to ''more cv-qualified'' types. In particular, the following conversions are allowed:
+
To convert a reference or a pointer to a cv-qualified type to a reference or pointer to a less cv-qualified type, {{rlpt|const_cast}} must be used.
 
+
:* reference/pointer to ''unqualified'' type can be converted to reference/pointer to  {{tt|const}}
+
:* reference/pointer to ''unqualified'' type can be converted to reference/pointer to {{tt|volatile}}
+
:* reference/pointer to ''unqualified'' type can be converted to reference/pointer to {{tt|const volatile}}
+
:* reference/pointer to {{tt|const}} type can be converted to reference/pointer to {{tt|const volatile}}
+
:* reference/pointer to {{tt|volatile}} type can be converted to reference/pointer to {{tt|const volatile}}
+
 
+
:Note: {{rlp|implicit_cast#Qualification_conversions | 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, {{rlp|const_cast}} must be used.
+
 
+
===Keywords===
+
 
+
{{ltt|cpp/keyword/const}},
+
{{ltt|cpp/keyword/volatile}},
+
{{ltt|cpp/keyword/mutable}}
+
  
 
===Notes===
 
===Notes===
The {{tt|const}} qualifier used on a declaration of a non-local non-volatile {{rev inl|since=c++14|non-{{rlp|variable template|template}}}}{{rev inl|since=c++17|non-{{rlp|inline}}}} variable that is not declared {{tt|extern}} gives it {{rlp|storage_duration#Linkage|internal linkage}}. This is different from C where const file scope variables have external linkage.
+
The {{c/core|const}} qualifier used on a declaration of a non-local non-volatile {{rev inl|since=c++14|non-{{rlp|variable template|template}}}}{{rev inl|since=c++17|non-{{rlp|inline}}}} variable that is not declared {{c/core|extern}} gives it {{rlp|storage duration#Linkage|internal linkage}}. This is different from C where const file scope variables have external linkage.
  
The C++ language grammar treats {{tt|mutable}} as a {{rlp|storage_duration|storage-class-specifier}}, rather than a type qualifier, but it does not affect storage class or linkage.
+
The C++ language grammar treats {{c/core|mutable}} as a {{rlp|storage duration|storage-class-specifier}}, rather than a type qualifier, but it does not affect storage class or linkage.
  
 
{{rrev|since=c++20|
 
{{rrev|since=c++20|
 
Some uses of volatile are deprecated:
 
Some uses of volatile are deprecated:
* lvalue of volatile type as operand of built-in {{rlp|operator_incdec|increment/decrement}} operators;
+
* lvalue of volatile type as operand of built-in {{rlp|operator incdec|increment/decrement}} operators;
* lvalue of volatile type as left operand of built-in {{rlp|operator_assignment|direct/compound assigment}} operators, unless the direct assigment expression appears in an {{rlp|expressions#Unevaluated_expressions|unevaluated context}} or is a {{rlp|expressions#Discarded-value_expressions|discarded-value expression}};
+
* lvalue of volatile type as left operand of built-in {{rlp|operator assignment|direct assignment}}<!-- P2327R1, CWG2654 -->, unless the direct assignment expression appears in an {{rlp|expressions#Unevaluated expressions|unevaluated context}} or is a {{rlp|expressions#Discarded-value expressions|discarded-value expression}};
 
* volatile object type as function parameter type or return type;
 
* volatile object type as function parameter type or return type;
 
* volatile qualifier in {{rlp|structured binding}} declaration.
 
* volatile qualifier in {{rlp|structured binding}} declaration.
 
}}
 
}}
 +
 +
===Keywords===
 +
{{ltt|cpp/keyword/const}},
 +
{{ltt|cpp/keyword/volatile}},
 +
{{ltt|cpp/keyword/mutable}}
  
 
===Example===
 
===Example===
 
{{example
 
{{example
|code=int main()
+
|code=
 +
#include <cstdlib>
 +
 
 +
int main()
 
{
 
{
     int n1 = 0;           // non-const object
+
     int n1 = 0;         // non-const object
     const int n2 = 0;     // const object
+
     const int n2 = 0;   // const object
     int const n3 = 0;     // const object (same as n2)
+
     int const n3 = 0;   // const object (same as n2)
     volatile int n4 = 0; // volatile object
+
     volatile int n4 = 0; // volatile object
 +
   
 
     const struct
 
     const struct
 
     {
 
     {
 
         int n1;
 
         int n1;
 
         mutable int n2;
 
         mutable int n2;
     } x = {0, 0};     // const object with mutable member
+
     } x = {0, 0};       // const object with mutable member
 
+
   
     n1 = 1; // ok, modifiable object
+
     n1 = 1;   // OK: modifiable object
//  n2 = 2; // error: non-modifiable object
+
//  n2 = 2;   // error: non-modifiable object
     n4 = 3; // ok, treated as a side-effect
+
     n4 = 3;   // OK: treated as a side-effect
 
//  x.n1 = 4; // error: member of a const object is const
 
//  x.n1 = 4; // error: member of a const object is const
     x.n2 = 4; // ok, mutable member of a const object isn't 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
 
     const int& r1 = n1; // reference to const bound to non-const object
 
//  r1 = 2; // error: attempt to modify through reference to const
 
//  r1 = 2; // error: attempt to modify through reference to const
     const_cast<int&>(r1) = 2; // ok, modifies non-const object n1
+
     const_cast<int&>(r1) = 2; // OK: modifies non-const object n1
 
+
   
 
     const int& r2 = n2; // reference to const bound to const object
 
     const int& r2 = n2; // reference to const bound to const object
 
//  r2 = 2; // error: attempt to modify through reference to const
 
//  r2 = 2; // error: attempt to modify through reference to const
 
//  const_cast<int&>(r2) = 2; // undefined behavior: attempt to modify const object n2
 
//  const_cast<int&>(r2) = 2; // undefined behavior: attempt to modify const object n2
 +
   
 +
    [](...){}(n3, n4, x, r2); // see also: [[maybe_unused]]
 +
   
 +
    std::system("g++ -O3 -Wa,-adhln ./main.cpp"); // may issue asm on POSIX systems
 
}
 
}
| output=
+
|p=true
 +
|output=
 
# typical machine code produced on an x86_64 platform
 
# typical machine code produced on an x86_64 platform
 
# (only the code that contributes to observable side-effects is emitted)
 
# (only the code that contributes to observable side-effects is emitted)
Line 125: Line 152:
 
     ret
 
     ret
 
}}
 
}}
 +
 +
===Defect reports===
 +
{{dr list begin}}
 +
{{dr list item|wg=cwg|dr=1428|std=C++98|before=the definition of 'const object' was based on declaration|after=based on object type}}
 +
{{dr list item|wg=cwg|dr=1528|std=C++98|before=there was no requirement on the number of occurrences<br>of each cv-qualifier in the same cv-qualifier sequence|after=at most once for<br>each cv-qualifier}}
 +
{{dr list item|wg=cwg|dr=1799|std=C++98|before={{c/core|mutable}} could be applied to data members not declared<br>{{c/core|const}}, but the members' types may still be const-qualified|after=cannot apply {{c/core|mutable}} to data<br>members of const-qualified types}}
 +
{{dr list end}}
  
 
===See also===
 
===See also===
 
{{dsc begin}}
 
{{dsc begin}}
{{dsc see c | c/language/const | {{tt|const}} qualifier | nomono=true}}
+
{{dsc see c|c/language/const|{{c/core|const}} qualifier|nomono=true}}
{{dsc see c | c/language/volatile | {{tt|volatile}} qualifier | nomono=true}}
+
{{dsc see c|c/language/volatile|{{c/core|volatile}} qualifier|nomono=true}}
 
{{dsc end}}
 
{{dsc end}}
  
 
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}
 
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}

Latest revision as of 15:31, 12 August 2024

 
 
C++ language
General topics
Flow control
Conditional execution statements
if
Iteration statements (loops)
for
range-for (C++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until C++17*)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
explicit (C++11)
static

Special member functions
Templates
Miscellaneous
 
 

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

  • const - defines that the type is constant.
  • volatile - defines that the type is volatile.

Contents

[edit] Explanation

Any (possibly incomplete) type other than function type or reference type is a type in a group of the following four distinct but related types:

  • A cv-unqualified version.
  • A const-qualified version.
  • A volatile-qualified version.
  • A const-volatile-qualified version.

These four types in the same group have the same representation and alignment requirements.

Array types are considered to have the same cv-qualification as their element types.

[edit] const and volatile objects

When an object is first created, the cv-qualifiers used (which could be part of decl-specifier-seq or part of a declarator in a declaration, or part of type-id in a new-expression) determine the constness or volatility of the object, as follows:

  • A const object is
  • 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.
  • A volatile object is
  • an object whose type is volatile-qualified,
  • 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.) made through a glvalue expression of volatile-qualified type is treated as a visible side-effect for the purposes of optimization (that is, within a single thread of execution, volatile accesses cannot be optimized out or reordered with another visible side effect that is sequenced-before or sequenced-after the volatile access. This makes volatile objects suitable for communication with a signal handler, but not with another thread of execution, see std::memory_order). Any attempt to access a volatile object through a glvalue of non-volatile type (e.g. through a reference or pointer to non-volatile type) results in undefined behavior.
  • A const volatile object is
  • 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.

Each cv-qualifier (const and volatile) can appear at most once in any cv-qualifier sequence. For example, const const and volatile const volatile are not valid cv-qualifier sequences.

[edit] mutable specifier

  • mutable - permits modification of the class member declared mutable even if the containing object is declared const (i.e., the class member is mutable).

May appear in the declaration of a non-static class members of non-reference non-const type:

class X
{
    mutable const int* p; // OK
    mutable int* const q; // ill-formed
    mutable int&       r; // ill-formed
};

mutable is used to specify that the member does not affect the externally visible state of the class (as often used for mutexes, memo caches, lazy evaluation, and access instrumentation).

class ThreadsafeCounter
{
    mutable std::mutex m; // The "M&M rule": mutable and mutex go together
    int data = 0;
public:
    int get() const
    {
        std::lock_guard<std::mutex> lk(m);
        return data;
    }
 
    void inc()
    {
        std::lock_guard<std::mutex> lk(m);
        ++data;
    }
};

[edit] Conversions

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

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

References and pointers to cv-qualified types can be implicitly converted to references and pointers to more cv-qualified types, see qualification conversions for details.

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.

[edit] Notes

The const qualifier used on a declaration of a non-local non-volatile non-template(since C++14)non-inline(since C++17) variable that is not declared extern gives it internal linkage. This is different from C where const file scope variables have external linkage.

The C++ language grammar treats mutable as a storage-class-specifier, rather than a type qualifier, but it does not affect storage class or linkage.

Some uses of volatile are deprecated:

(since C++20)

[edit] Keywords

const, volatile, mutable

[edit] Example

#include <cstdlib>
 
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
    {
        int n1;
        mutable int n2;
    } x = {0, 0};        // const object with mutable member
 
    n1 = 1;   // OK: modifiable object
//  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 non-const object 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 n2
 
    [](...){}(n3, n4, x, r2); // see also: [[maybe_unused]]
 
    std::system("g++ -O3 -Wa,-adhln ./main.cpp"); // may issue asm on POSIX systems
}

Possible 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

[edit] Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
CWG 1428 C++98 the definition of 'const object' was based on declaration based on object type
CWG 1528 C++98 there was no requirement on the number of occurrences
of each cv-qualifier in the same cv-qualifier sequence
at most once for
each cv-qualifier
CWG 1799 C++98 mutable could be applied to data members not declared
const, but the members' types may still be const-qualified
cannot apply mutable to data
members of const-qualified types

[edit] See also

C documentation for const qualifier
C documentation for volatile qualifier