const Qualifier
Because we can’t change the value of a const object after we create it, it must be initialized just as reference
const int i = get_size(); // ok: initialized at run time
const int j = 42; // ok: initialized at compile time
const int k; // error: k is uninitialized const
when we use an object to initialize another object, it doesn’t matter whether either or both of the objects are consts.
int i = 42;
const int ci = i; // ok: the value in i is copied into ci
int j = ci; // ok:the value in ci is copied into j
By Default, const Objects Are Local to a File
When we really need to share const between files, define a single instance of a const variable, we use the keyword extern on both its definition and declaration(s).
// file_1.cc defines and initializes a const that is accessible to other files
extern const int bufSize = fcn();
// file_1.h
extern const int bufSize; // same bufSize as defined in file_1.cc
References to const
const int ci = 1024;
const int &r1 = ci; // ok: both reference and underlying object are const
r1 = 42; // error: r1 is a reference to const
int &r2 = ci; // error: non const reference to a const object
exception
we noted that there are two exceptions to the rule that the type of a reference must match the type of the object to which it refers. The first exception is that we can initialize a reference to const from any expression that can be converted (§ 2.1.2, p. 35) to the type of the reference.
int i = 42;
const int &r1 = i; // we can bind a const int& to a plain int object
const int &r2 = 42; // ok: r2 is a reference to const
const int &r3 = r1 * 2; // ok: r3 is a reference to const
int &r4 = r1 * 2; // error: r4 is a plain, non const reference
A reference to const may refer to an object that is not const
int i = 42;
int &r1 = i; // r1 bound to i
const int &r2 = i; // r2 also bound to i; but cannot be used to change i
r1=0; // r1 isnot const;i isnow 0
r2 = 0; // error: r2 is a reference to const
Pointers and const
A const pointer/reference/value can = (initialized with) a const or non-const, but a non-const cannot = to a const
const double pi = 3.14; // pi is const; its value may not be changed
double *ptr = π // error: ptr is a plain pointer
const double *cptr = π // ok: cptr may point to a double that is const
*cptr = 42; // error: cannot assign to *cptr
Const pointer
pointer itself is const
Like any other const object, a const pointer must be initialized and once initialized, its value may not be changed
The fact that a pointer is itself const says nothing about whether we can use the pointer to change the underlying object. Whether we can change that object depends entirely on the type to which the pointer points.
int errNumb = 0;
int *const curErr = &errNumb; // curErr will always point to errNumb
const double pi = 3.14159;
const double *const pip = π // pip is a const pointer to a const object
Top-level const
Top-level const to indicate that a pointer itself is a const.
when a pointer to a const object, we refer to that const as a low-level const.
when copy an object, the low-level const should be the same. i.e., both should have the pointed object as const.
int i = 0;
int *const p1 = &i; // we can't change the value of p1; const is top-level
const int ci = 42; // we cannot change ci; const is top-level
const int *p2 = &ci; // we can change p2; const is low-level
const int *const p3 = p2; // right-most const is top-level, left-most is not
const int &r = ci; // const in reference types is always low-level
i = ci; // ok: copying the value of ci; top-level const in ci is ignored
p2 = p3; // ok: pointed-to type matches; top-level const in p3 is ignored
int *p = p3; // error: p3 has a low-level const but p doesn't
p2 = p3; // ok: p2 has the same low-level const qualification as p3
p2 = &i; // ok: we can convert int* to const int*
int &r = ci; // error: can't bind an ordinary int& to a const int object
const int &r2 = i; // ok: can bind const int& to plain int
constexpr and constant expressions
declare constexpr for compiler to verify that it is a constant expression
Variables declared as constexpr are implicitly const and must be initialized by constant expressions
constexpr int mf = 20; // 20 is a constant expression
constexpr int limit = mf + 1; // mf + 1 is a constant expression
constexpr int sz = size(); // ok only if size is a constexpr function
Although we cannot use an ordinary function as an initializer for a constexpr variable, we’ll see in § 6.5.2 (p. 239) that the new standard lets us define certain functions as constexpr. Such functions must be simple enough that the compiler can evaluate them at compile time. We can use constexpr functions in the initializer of a constexpr variable.
Literal types
The arithmetic, reference, and pointer types are literal types.
when pointers and reference are defined as constexpr, they need to point to or refer to objects that remains at a fixed address
such as variables defined inside a function can not be pointed to, because they are not stored at a fixed address. See § 6.1.1 for details.
There are variables defined outside any function, those special object also have fixed addresses, so can be used as the target object.
Pointers and constexpr
when we define a pointer in a constexpr declaration, the constexpr specifier applies to the pointer, not the type to which the pointer points.
constexpr int *np = nullptr; // np is a constant pointer to int that is null int j = 0;
constexpr int i = 42; // type of i is const int
// i and j must be defined outside any function
constexpr const int *p = &i; // p is a constant pointer to the const int i
constexpr int *p1 = &j; // p1 is a constant pointer to the int j
Comments
Post a Comment