C + + in the const and constexpr detailed _c language

Source: Internet
Author: User
Tags array length constant int size modifier

The const in C + + can be used to modify variables, functions, and have different meanings in different places, as summarized below.

The semantics of the const

The purpose of const in C + + is to guarantee the constant nature of objects through the compiler, forcing the compiler to treat all operations that might violate the Const object as error.

The constants of objects can be divided into two types: physical constants (i.e., each bit immutable) and logical constants (that is, the object's performance remains unchanged). In C + +, physical constants are used, such as the following example:

struct A {
  int *ptr;
};
int k = 5, R = 6;
Const a A = {&k};
A.ptr = &r; !error
*a.ptr = 7;//No error

A is a const object, the assignment to any member of a is treated as error, but if the PTR is not changed, the compiler does not make an error if it changes the object that the PTR points to. This is actually a violation of the logic constants because the performance of a has changed!

Another feature of logical constants is that the Const object can have fields that are not visible to some users, and changing them does not violate logical constants. Examples in effective C + + are:

Class Ctextblock {public 
: 
  ... 
  std::size_t length () const; 
Private: 
  char *ptext; 
  std::size_t TextLength;      Last calculated length of TextBlock 
  bool Lengthisvalid;        Whether length is currently valid 
};

The Ctextblock object will cache the current length to the TextLength member each time it calls the length method, while the Lengthisvalid object represents the validity of the cache. In this scenario, TextLength and Lengthisvalid, if changed, do not violate the logical constants of the Ctextblock object, but are blocked by the compiler because they change some bit in the object. C + + To solve this problem, added the mutable keyword.

This section concludes that the semantics of const in C + + are guaranteed to be physical constants, but some of the logical constants can be supported by mutable keywords.

const modifier Variable

As described in the previous section, the semantics of the const modifier variable is to require the compiler to block all assignment behavior to that variable. Therefore, you must provide an initial value to the const variable when it is initialized:

const int i;
i = 5; !error
const INT j = Ten;//OK

This initial value can be either a compile-time or a value that is determined by the runtime. If you give a compile-time initial value to a const variable of an integer type, you can use this variable as the length of the declared array:

const int compile_const = ten;
const int runtimeconst = Cin.get ();
int A1[complie_const]; OK in C + + and error in C
int a2[runtimeconst];//!error in C + +

Because the C + + compiler can replace the compilation time that appears in the array length directly with its literal value, it is equivalent to an automatic macro substitution. (GCC validation found that only the array length was replaced directly, while other places that were assigned with Compile_const were not replaced.) )

The const variable for a file field is visible in the file, and if you need to use the const variable m in A.cpp in B.cpp, you need to add extern at the initialization of M:

A.cpp
extern const int M =;
 
B.cpp
extern const int M;

It is generally assumed that placing the definition of a variable in the. h file will cause all. cpp files that include the. h file to have this variable defined, which can cause conflicts when linked. However, it is possible to place the definition of a const variable in the. h file, and the compiler will put this variable into the anonymous namespace of each. cpp file, thus belonging to a different variable without causing a link conflict. (Note: However, if the initial value of the const amount in the header file relies on a function, and the return value of the function is not fixed each time it is called, the value of the const in the different compilation units is not equal.) Guess: This problem may be resolved by having the const as a static member of a class at this time. )

const modifier pointers and references

The const modifier reference has the same meaning as the decorated variable. But when the const modifies the pointer, the rules are somewhat complicated.

Simply put, the type of the pointer variable can be divided into two parts of the nearest ' * ' to the left of the variable name, and the right-hand part represents the character of the pointer variable, while the left part indicates the nature of the element:

const int *P1; P1 is a non-const pointer and points to a const int
int * const P2;//P2 be a const pointer and points to a Non-co NST int
const INT * const P3;//p3 is a const pointer and points to a const it
const int *PA1[10];//PA1 are an A Rray and contains non-const pointer point to a const int
int * const PA2[10];//PA2 be an array and contains CO NST Pointer point to a non-const int
const INT (* p4) [ten];//P4 is a non-const pointer and points to an array contain s const int
const INT (*PF) ()//PF is a non-const pointer and points to a function which has no arguments and RET Urns a const int
...

The rules for how to interpret the const pointers are pretty much the same ...

The pointer itself is a const, which means that the pointer cannot be assigned, whereas a const object indicates that it cannot be assigned a value. The reference can therefore be viewed as a pointer to itself as const, whereas a const reference is a const TYPE * const pointer.

A pointer to const is a pointer that cannot be assigned to a non-const, nor can a const reference assign a value to a non-const reference, but in turn there is no problem, which is to ensure that the const semantics are not corrupted.

You can use Const_cast to remove the const nature of a pointer or reference, or use static_cast to add a const character to a non-const pointer or reference:

int i;
const int *CP = &i;
int *p = Const_cast<int *> (CP);
const int *CP2 = static_cast<const int *> (p); Here's the static_cast is optional

The this pointer in the C + + class is a pointer to a const itself, whereas the this pointer in the const method of the class is both itself and a pointer to a const.

Const member variable in a class

The const member variables in a class can be divided into two types: non-static constants and static constants.

Non-static constants:
A non-static constant in a class must be initialized in the initialization list of the constructor. Because the non-static members of a class are constructed before entering the function body of the constructor, the const constant must be initialized at construction time, and the constructed assignment will be blocked by the compiler.

Class B {public
:
  B (): Name ("AAA") {
    name = "BBB";//!error
  }
Private:
  const std::string name;
};

Static constants:
A static constant is declared directly in a class, but to have a unique definition and initial value outside of the class, the common method is to include the definition of the static constant of the class in the corresponding. CPP:

A.H
class A {
  ...
  static const std::string name;
 
A.cpp
const std::string a::name ("AAA");

A special case is that if the type of the static constant is a built-in integer type, such as char, int, size_t, and so on, then the initial value can be given directly in the class without having to be defined outside the class. The compiler replaces this static constant directly with the corresponding initial value, which is equivalent to a macro substitution. But if we use this static constant in our code like a normal variable, if you take its address instead of using its value like a macro, we still need to give it a definition outside of the class, but we don't need an initial value (because we already have it at the declaration).

A.H
class A {
  ...
  static const int SIZE =;
 
a.cpp
const INT a::size =//If use SIZE as a variable, not a macro

Const modifier function

In C + +, you can use const to modify a class's non-static member function, whose semantics is to guarantee the const of the object itself that corresponds to the function. In a const member function, all operations that can violate this pointer const (the this pointer in a const member function is a double const pointer) are blocked, such as assigning to other member variables and the non-const method that invokes them. The non-const method that invokes the object itself. However, any action done on a member variable declared as mutable will not be blocked. This ensures a certain degree of logical constants.

In addition, the const modifier function also participates in the overload of the function, that is, the Const method is invoked preferentially when the method is called by a const object, a const pointer, or a reference.

Class A {public
:
  int &operator[] (int i) {
    ++cachedreadcount;
    return data[i];
  }
  const int &operator[] (int i) const {
    ++size;//!error
    --size;//!error
    ++cachedreadcount;//OK
    re Turn data[i];
  }
Private:
  int size;
  mutable Cachedreadcount;
  std::vector<int> data;
 
A &a = ...;
Const A &CA = ...;
int i = a[0]; Call operator[]
int j = ca[0] (//Call const operator[]
a[0] = 2;//OK
ca[0] = 2;//!error

In this case, if two versions of operator[] have essentially the same code, consider calling another function in one of the functions to reuse the code (refer to effective C + +). Here we can only invoke the const version with a non-const version.

int &a::operator[] (int i) {return
  const_cast<int &> (static_cast<const A &> (*this). Operator[] (i));

In order to avoid invoking itself causing a dead loop, the first step is to convert the *this to const A, which can be accomplished using static_cast. After obtaining the return value of the const operator[], you also manually remove its const, which can be done using const_cast. Generally speaking, const_cast is not recommended, but here we know clearly that the object we are dealing with is not a const, so it is safe to use const_cast here.

constexpr

CONSTEXPR is the new keyword in c++11, whose semantics are "constant expressions," which are expressions that can be evaluated at compile time. The most fundamental constant expression is the result of a literal or global variable/function address, or a keyword returned by a sizeof, while the other constant expressions are derived from a variety of determined operations by the underlying expression. The constexpr value can be used for an enum, switch, array length, and so on.

CONSTEXPR the modified variable must be evaluated at compile time, and the modified function will definitely return constexpr when all its parameters are constexpr.

constexpr int Inc (int i) {return
  i + 1;
}
 
constexpr int a = INC (1); OK
constexpr int b = INC (Cin.get ());//!error
constexpr int c = A * 2 + 1;//OK

Constexpr can also be used to modify the constructor of a class to ensure that if the arguments supplied to the constructor are constexpr, all members of the resulting object will be constexpr, which is the Constexpr object, Can be used for a variety of occasions that can only use constexpr. Note that the Constexpr constructor must have an empty function body, that is, the initialization of all member variables is placed in the initialization list.

struct a {
  constexpr a (int xx, int yy): X (xx), Y (yy) {}
  int x, y;
};
 
Constexpr A (1, 2);
enum {size_x = a.x, size_y = a.y};

Benefits of constexpr:

is a strong constraint to better ensure that the correct semantics of the program are not corrupted.
Compilers can perform very large optimizations of constexpr code at compile time, such as replacing the constexpr expressions used directly with the final results.
Compared to macros, there is no extra overhead, but it's safer and more reliable.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.