Mutable keyword
Mutable is an uncommon keyword in C ++. It can only be used for non-static and non-constant data members of a class.
We know that the state of an object is determined by the non-static data member of the object. As the data member changes,
The status of the object also changes!
If a member function of a class is declared as the const type, this function will not change the object state, that is
This function does not modify non-static data members of the class, but sometimes it is necessary
Assign a value. This requires the mutable keyword.
For example:
|
Class demo { Public: Demo (){} ~ Demo (){} Public: Bool getflag () const { M_naccess ++; Return m_bflag; } PRIVATE: Int m_naccess; Bool m_bflag; };Int main () { Return 0; } |
Compile the above Code and the error c2166: L-value specifies const object will appear.
It indicates that the non-static data member of the class is changed in the const type function.
In this case, you need to use mutable to modify the non-static data member to be changed in the const member function.
M_naccess, the Code is as follows:
|
Class demo { Public: Demo (){} ~ Demo (){} Public: Bool getflag () const { M_naccess ++; Return m_bflag; } PRIVATE: Mutable int m_naccess; Bool m_bflag; };Int main () { Return 0; } |
In this way, no errors will occur during re-compilation!
Volatile keywords
Volatile is a little-known keyword in C/C ++ that tells the compiler not to hold a temporary copy of a variable. It can be applied to basic types.
For example, Int, Char, long... also applies to the structure of C and the class of C ++. When the structure or Class Object is modified using volatile, the structure or
All the members of the class will be considered volatile.
Using volatile does not deny the need for synchronization objects such as critical_section, mutex, and event.
For example:
Int I;
I = I + 3;
In any case, I will always be placed in a register for a short period of time, because arithmetic operations can only be performed in registers. In general, volatitle
The keyword applies to rows rather than rows.
Let's first implement a simple function to observe the deficiencies in the compilation code generated by the compiler and how to correct the volatile keyword.
This deficiency. There is a busy loop in this function (the so-called busy loop is also called Busy waits, which is a high waste of CPU time)
|
Void getkey (char * PCH) { While (* PCH = 0) ; } |
After you close all the optimization options in the VC development environment, compile the program and obtain the following results (assembly code)
|
; While (* PCH = 0) $ L27 ; Load the address stored in PCH MoV eax, dword ptr _ PCH $ [EBP] ; Load the character into the eax register Movsx eax, byte PTR [eax] ; Compare the value to zero Test eax, eax ; If not zero, exit Loop JNE $ l28 ; JMP $ L27 $ L28 ;} |
This section of unoptimized code constantly loads the appropriate address, loads the content in the address, and tests the results. The efficiency is quite low, but the results are very accurate
Now let's take a look at all the compiler's optimization options after the switch is turned on, re-compile the program, the generated assembly code, and the above Code
What are the differences?
|
;{ ; Load the address stored in PCH MoV eax, dword ptr _ PCH $ [esp-4] ; Load the character into the Al register Movsx Al, byte PTR [eax] ; While (* PCH = 0) ; Compare the value in the Al register to zero Test Al, Al ; If still zero, try again Je short $ l84 ; ;} |
The code length is much shorter than that without optimization. Note that the compiler places the mov command out of the loop. This is a very good Optimization in a single thread. However, in a multi-threaded application, if another thread changes the variable value, the loop will never end. The tested value is always placed in the register. Therefore, this section of code has a huge bug in the case of multithreading. Solution: Re-
Write the getkey function once and declare the PCH parameter as volatile. The Code is as follows:
|
Void getkey (volatile char * PCH) { While (* PCH = 0) ; } |
This modification has no impact on the non-optimized version. The following figure shows the results after optimization:
|
;{ ; Load the address stored in PCH MoV eax, dword ptr _ PCH $ [esp-4] ; While (* PCH = 0) $ L84: ; Directly compare the value to zero CMP byte PTR [eax], 0 ; If still zero, try again Je short $ l84 ; ;} |
The modification results are perfect and the address will not change. Therefore, the address Declaration is moved out of the loop. The address content is volatile, so each loop
It is constantly re-checked.
It is legal to pass a const volatile variable as a parameter to the function. This declaration means that the function cannot change the value of the variable, but
The value can be changed by another thread at any time.
Explicit keywords
When writing an application, the explicit keyword is rarely used. Its function is to "prohibit Single-parameter constructors" and is used for automatic type conversion, A typical example is the container type. In this type of constructor, you can pass the initial length as a parameter to the constructor.
For example:
You can declare such a constructor
|
Class Array { Public: Explicit array (INT size ); ...... }; |
Here, the explicit keyword plays a vital role. Without this keyword, this constructor can convert int to array. once this happens, you can give the array tribe an integer without causing any problems, such:
In this case, the automatic type conversion of C ++ converts 40 to an array with 40 elements and assigns it to the ARR variable. This result is not the expected result at all. if we declare the constructor as explicit, the assignment operation above will cause the compiler to report an error so that we can detect the error in time. it should be noted that explicit can also prevent "initialization with transformation operations using the value assignment Syntax ";
For example:
Array Arr (40); // correct
Array arr = 40; // Error
Take a look at the following two operations:
X;
Y (x); // explicit type conversion
Another
X;
Y = x; // implicit type conversion
There is a small difference between the two operations. The first method generates a new object of Type Y based on Type X through explicit type conversion; the second method generates a new object of Type Y through implicit conversion.
The application of the explicit keyword is mainly the definition of the constructor mentioned above. You can refer to the application of this keyword to see the STL source code. This keyword is widely used.
_ Based keywords
This keyword is mainly used to solve some problems related to the shared memory. It allows the pointer to be defined as a 32-bit offset value starting from a certain point, rather than the absolute location of the memory type.
For example:
|
Typedef struct tagdemostruct { Int; Char SZ [10]; } Demostruct, * pdemostruct;Handle hfilemapping = createfilemapping (...); Lpvoid lpshare = (lpdword) mapviewoffile (...); Demostruct _ based (lpshare) * lpdemo; |
The above example declares a pointer lpdemo, which internally stores the offset value starting from lpshare, that is, the lphead is based on lpshare. the demostruct in the preceding example is just a structure defined randomly to represent any structure.
Although the _ Based pointer is very easy to use, you must pay a certain cost for efficiency. every time you use the _ Based pointer to process data, the CPU must add a base address for it to point to the real location.
Here I just introduced the meaning and usage of several frequently-seen keywords from time to time. There are many other articles about them that I will not describe them here. I hope this content will be helpful to you!
Referenced in http://www.pconline.com.cn/pcedu/empolder/gj/c/0412/514980.html