[C++] References, inline functions, etc.


1. Citation

1. Reference concept

A reference is not a new definition of a variable, but an alias for an existing variable . The compiler will not open up memory space for the reference variable, and it shares the same memory space with the variable it refers to .

Although the reference actually has space in the underlying implementation, because the reference is implemented according to the pointer method

How to use:
type & reference variable name (object name) = reference entity;

int n = 10;
int& m = n;
//m就是对n的一个引用

Notice: The reference type must be of the same type as the referenced entity

2. Citation properties

  1. References must be initialized when they are defined
  2. A variable can have multiple references
  3. Once a reference refers to an entity, it cannot refer to another entity
int n = 10;
int& m; //这条代码在编译时便会出错,就是因为定义时没有初始化

3. Permission issues when citing

In the process of referencing, permissions can be panned and zoomed out, but not zoomed in
It may be a bit abstract to say so, here is an example for readers:

const int a = 10;
int& ra = a; // a变量被const修饰,具有常性不可修改,
             //引用后属于权限放大
const int& ra = a; //正确做法

int& b = 10; // 10是常量,属于权限放大
const int& b = 10;//正确做法

double d = 12.34;
int& rd = d; // 类型不同,不能引用

4. Usage scenarios

  1. Make parameters
    In C language, for example, to realize the data exchange function, it must be called by address, because the change of the formal parameters does not affect the actual parameters. In C++, you can pass references directly, and you can directly access actual parameters through references.
	void Swap(int& left, int& right)
	{
    
    
	int temp = left;
	left = right;
	right = temp;
	}
  1. do return value
	int& Count()
	{
    
    
	static int n = 0;
	n++;
	// ...
	return n;
	}

One thing to note is that if the n variable is out of the function, it will be destroyed. At this time, accessing this address by reference will constitute an out-of-bounds.
That is, if the function returns out of the scope of the function, if the returned object is still there (not returned to the system), you can return by reference, and if it has been returned to the system, you must return by value.

In addition, when returning by value, the function does not directly pass the actual parameter or return the variable itself directly, but passes the actual parameter or returns a temporary copy of the variable, so using the value as the parameter or return value type is very inefficient, especially when the parameter or return value type is very large, the efficiency is even lower. Using return by reference can greatly improve efficiency.

5. The connection and difference between reference and pointer

As mentioned earlier, a reference is an alias in terms of grammatical concept, has no independent space, and shares the same space with its referenced entity. However, there is actually space in the underlying implementation, because references are implemented as pointers.

the difference:

  1. A reference conceptually defines an alias for a variable, and a pointer stores the address of a variable.
  2. References must be initialized when they are defined, pointers are not required
  3. After the reference refers to an entity during initialization, it cannot refer to other entities, and the pointer can point to any entity of the same type at any time
  4. There are no NULL references, but there are NULL pointers
  5. The meaning is different in sizeof: the reference result is the size of the reference type, but the pointer is always the number of bytes occupied by the address space (4 bytes under the 32-bit platform)
  6. The self-increment of the reference means that the referenced entity increases by 1, and the self-increment of the pointer means that the pointer offsets the size of a type backward
  7. Multi-level pointers, but no multi-level references
  8. There are different ways to access entities, the pointer needs to be explicitly dereferenced, and the reference compiler handles it by itself
  9. References are relatively safer to use than pointers

2. Inline functions

1. Concept

An inline function is a method to improve the efficiency of function execution. It can avoid the overhead of function calls by inserting a copy of the function body into each call site at compile time, that is, there is no overhead of function calls to build stack frames, and the efficiency of program operation is improved.
To define a function as an inline function, just add the keyword inline before the function definition. For example:

inline int max(int a, int b) {
    
    
  return (a > b) ? a : b;
}

2. Notes

  1. Inline is a method of exchanging space for time. If the compiler treats the function as an inline function, it will replace the function call with the function body at the compilation stage. Disadvantage: it may increase the size of the object file. Advantage: less call overhead and improve program operating efficiency.
  2. The inline function is just a suggestion to the compiler, and the compiler can decide whether to perform inline expansion according to its own judgment. In some cases, the compiler may not inline the inline function, for example:
    the function body is too large or too complex, including loops, branches, recursion and other structures.
    The function is virtual and a virtual call is made.
    The address of a function is taken or an indirect call is made through a pointer.
    The function uses inline assembly or the naked__declspec modifier.
    The function uses variable-length parameter lists or exception handling mechanisms.
  3. Inline does not recommend separation of declaration and definition, which will lead to link errors. Because inline is expanded, there is no function address, and the link will not be found.
  4. Member functions defined in a class are implicitly inlined by default, even if the inline keyword is not used. If you want to define an inline member function outside the class, you need to add the inline keyword when declaring it inside the class and when defining it outside the class.

Three, the auto keyword

1. Concept

The auto keyword is a type specifier introduced by C++11, which allows the compiler to infer the type of the variable based on the variable's initialization expression or the return value of the function. Using the auto keyword can simplify the code, avoid repetitive input of lengthy or complex type names, and improve the readability and maintainability of the code.

//使用auto关键字
auto i = 42; //i的类型是int
auto d = 3.14; //d的类型是double
auto s = "hello"; //s的类型是const char*
auto f = [](int x) {
    
     return x * x; }; //f的类型是一个lambda表达式

//不使用auto关键字
int i = 42;
double d = 3.14;
const char* s = "hello";
auto f = [](int x) {
    
     return x * x; }; //f的类型是一个lambda表达式

【Notice】
When using auto to define a variable, it must be initialized. At the compilation stage, the compiler needs to deduce the actual type of auto according to the initialization expression. Therefore, auto is not a "type" declaration, but a "placeholder" when the type is declared. The compiler will replace auto with the actual type of the variable during compilation.

2. The usage rules of auto

  1. The auto keyword cannot be used alone, and must be used with an initialization expression or function return value, otherwise the compiler cannot infer the type of the variable.
  2. When declaring multiple variables on the same line, these variables must be of the same type, otherwise the compiler will report an error, because the compiler actually only deduces the first type, and then defines other variables with the deduced type.
auto a = 1, b = 2;
auto c = 3, d = 4.0; // 该行代码会编译失败,因为c和d的初始化表达式类型不同
  1. The auto keyword can be used with other type modifiers (such as const, volatile, *, &, etc.), for example, const auto& x = y;to indicate that x is a constant reference whose type is determined by y.
  2. The auto keyword ignores top-level const and references unless explicitly specified. For example auto x = 42;and auto x = &42;will infer that the type of x is int, not const int or int&.
  3. The auto keyword cannot be used for function parameters or template parameters, because these places need to explicitly specify the type. However, it can be used for function return values. If there is a return statement in the function body, the compiler will infer the type of the return value based on the expression of the return statement.
  4. auto cannot be used directly to declare arrays
    auto a[] = {
          
          1,2,3};
    
  5. The auto keyword cannot be used for coercion or operators (such as sizeof, typeid, etc.), because these places require a specific type name, not a placeholder.

4. Range-based for loop

1. Concept

C++'s range-based for loop is a new loop syntax introduced by C++11, which allows the compiler to traverse each element in a container or array according to the range without explicitly using iterators or subscripts. Using a range-based for loop can simplify the code and improve the readability and maintainability of the code. For example:

//使用基于范围的for循环
vector<int> vec = {
    
    1, 2, 3, 4, 5};
for (int x : vec) //x是vec中每个元素的拷贝
{
    
    
    cout << x << " ";
}
cout << endl;

//不使用基于范围的for循环
vector<int> vec = {
    
    1, 2, 3, 4, 5};
for (vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) //it是vec中每个元素的迭代器
{
    
    
    cout << *it << " ";
}
cout << endl;

Note: Similar to ordinary loops, you can use continue to end this loop, or use break to jump out of the entire loop.

2. Conditions for the use of scope for

  1. The range of the for loop iteration must be determined.
    For an array, it is the range of the first element and the last element in the array; for a class, methods of begin and end should be provided, and begin and end are the range of the for loop iteration.
  2. The iterated object must implement ++ and == operations.

Five, the pointer null value nullptr

1. Concept

The C++ pointer nullptr is a new keyword introduced by C++11, which is used to represent a null pointer, that is, a pointer that does not point to any object or function. Using nullptr can avoid using NULL or 0 to initialize the null pointer, thus improving the readability and maintainability of the code.

2. Use caution

    1. When using nullptr to represent the null value of the pointer, there is no need to include the header file, because nullptr was introduced as a new keyword in C++11.
  1. nullptr is a special literal that can be implicitly converted to any pointer type or boolean type, but not to other types. For example int x = nullptr; is wrong because nullptr cannot be converted to int type.
  2. The type of nullptr is nullptr_t, which is a special data type used to represent a null pointer. nullptr_t has only one value, which is nullptr. You can use decltype(nullptr) to get the type of nullptr_t.
  3. nullptr can be used to compare whether a pointer is null, or to compare whether two null pointers are equal. For example, if (p == nullptr) means to judge whether p is a null pointer; if (p == q) means to judge whether p and q are both null pointers.

Guess you like

Origin blog.csdn.net/lyq2632750277/article/details/131857447