C++-reference, inline function


1. What is a reference?

The reference is not a new variable, but an alias for an existing variable. The compiler will not open up a new memory space for the reference variable, and the reference and the referenced variable share a memory space.

A reference gives another name to an object, and a reference type refers to another type. Define the reference type by writing the declarator in the form of &d, where d is the declared variable name:

    int val = 100;
    int &refval = val;//refval指向val(是val另一个名字)
    int &refval2;//会报错:引用必须被初始化。

1.1 Referenced characteristics

1. The reference must be initialized
Q1: Why must the reference be initialized?
Generally, when initializing a variable, the initial value will be copied to the newly created object. However, when defining a reference, the program binds the reference to its initial value instead of copying the initial value to the reference. Once the initialization is complete, the reference will always be bound to its initial value object. Because it is not possible to rebind the reference to another object, the reference must be initialized.
2. A variable can have multiple references
3. Once a reference is referenced to an entity, other entities can no longer be referenced

   int val = 10;
   int val_1 = 20;
   int &ra = val;
   int &ra = val_1;//会报错:因为ra已经与val绑定,再不能引用其他实体。
   int &rra = val;//一个实体(变量)可以有多个引用

Notes: A new type of reference has been added in C++11: the so-called "rvalue reference". This reference is mainly used for built-in classes. Strictly speaking, when we use the term "reference", we are actually referring to "lvalue references."

1.2 Frequently quoted (reference to const)

In basic references, all reference types must strictly match the objects bound to them (with exceptions). Moreover, references can only be bound to objects, not to literal values ​​or the calculation result of an expression.

   const int a = 10;
   int &ra = a;//错误:a为常量
   const int &ri = a;//正确:引用以及其对应的对象都是常量。
   const int a = 10;
   int &ra = a;//错误:a为常量
   const int &ri = a;//正确:引用以及其对应的对象都是常量。
   ri = 42;//错误:ri是对常量的引用
   int &rb = a;//错误:试图让一个非常量引用指向一个常量对象。

As mentioned above: the referenced type must be consistent with the type of the object it refers to, but there are exceptions. The first exception is that any expression is allowed as the initial value when initializing a constant reference, as long as the result of the expression can be converted to the reference type.

We can take a look at what happens when a constant reference is bound to another type:

   double d = 12.34;
   //int &rd = d;//错误:因为类型不同
   const int& rd = d;//为什么就正确了?

Here rd refers to an integer of type int. The operation on rd should be an integer operator, but d is a double-precision floating-point number rather than an integer. Therefore, in order to ensure that rd is bound to an integer, the compiler turns the above code into the following form:

   const int temp = d;//由双精度浮点数生成一个临时的整形常量
   const int& rd = temp;//让rd绑定这个常量

In this case, rd binds a temporary object. The so-called temporary object is an unnamed object created when the compiler needs a space to temporarily store the evaluation result of an expression. Note that the object bound by rd is a temporary, not d.

1.3 Reference usage scenarios

1. Make parameters

void Swap(int& left,int& right)
{
    
    
    int tmp = left;
    left = right;
    right = tmp;
}

2. Make the return value

int& Count()
{
    
    
    static  int n = 0;
    n++;
    //.....
    return n;
}

Q: What is the result of the following code?

#include <iostream>
using namespace std;
int& Add (int a,int b)
{
    
    
    int c = a + b;
    return c;
}
int main()
{
    
    
    int& ret = Add(1,2);
    Add(3,4);
    std::cout<<"Add(1,2) = "<<ret<<endl;
    return 0;
}

Note: If the function returns out of the scope of the function, if the returned object is not returned to the system, you can use the return by reference, and you can use the return by reference. If it has been returned to the system, you must use the return by value.
All of the above programs roll back the stack frame after the life cycle of the function ends, and the address pointed to by the reference is not necessarily safe and accessible.
To sum up: Don't quote back to local variables.

In response to this problem, if rewritten as:

#include <iostream>
using namespace std;
int& Add (int a,int b)
{
    
    
    static int c = a + b;
    return c;
}
int main()
{
    
    
    int& ret = Add(1,2);
    Add(3,4);
    std::cout<<"Add(1,2) = "<<ret<<endl;
    return 0;
}

Then there will be some changes in the result (this foreshadowing, save it for future review).

1.4 Comparison of the efficiency of passing by value and passing by reference

Use value as a parameter or return value type. During parameter passing and return, the function will not directly pass actual parameters or return the variable itself. Knowing that passing actual parameters or returning a temporary copy of the variable, use the value as a parameter or return Value type, efficiency is very low. The reference does not open up new memory space, so it is extremely efficient.

1.5 The difference between references and pointers

A reference is an alias in the grammatical concept. There is no independent space, and it shares the same memory space with the object it refers to. But the reference is actually by space in the underlying implementation, because the trigger is implemented in the way of pointers.
Insert picture description here
Insert picture description here
The difference between references and pointers:
1. References must be initialized when they are defined, and pointers are not required.
2. After referencing an entity during initialization, you can no longer refer to other entities, and the pointer can point to any entity of the same type at any time.
3. The reference does not have a NULL reference, but there is a NULL pointer.
4. The size is different, the size of the reference is the size of its own reference type, and the size of the pointer is fixed at 4 bytes (32-bit platform)
5. The reference is added to the entity that is referenced, and the pointer is added to the pointer to be backward. Shift the size of a type.
6. There are multi-level pointers, but no multi-level references.
7. The way to access the entity is different, the pointer needs to be dereferenced, and the reference is handled by the compiler itself.
8. References are relatively safer to use than pointers.

Two, inline function

1. What is an inline function

A function decorated with inline is called an inline function. When compiling, the C++ compiler will expand where the inline function is used. There is no overhead of function pushing on the stack. Inline function can improve the efficiency of program operation.

2. Features of inline functions

1. Inline function is a practice of changing the time zone by space, which saves the extra overhead of calling the function. So when the code is very long, looped or recursive, it is not suitable to use inline functions.

2. Inline function is just a suggestion for the compiler, the compiler will automatically optimize, if there is a loop or recursion in the function body defined as inline, the compiler will automatically ignore the inline function when optimizing.

3. Inline is not recommended to separate declaration and definition. Separation will lead to link errors. Because inline is expanded, there is no function address and the link will not be found.

Three, auto keyword (C++11)

In C++11, the Standards Committee gave a new definition of auto: auto is no longer a storage type indicator, but as a new type indicator to instruct the compiler. Variables declared by auto must be declared by the compiler at compile time. Derived.

using namespace std;
int TestFun()
{
    
    
    return 10;
}
int main()
{
    
    
    int a = 10;
    auto b = a;
    auto c = b;
    auto d = TestFun();
    return  0;
}

Note: When using auto to define a variable, it must be initialized. During the compilation phase, the compiler needs to push the actual type of auto according to the initialization expression. Therefore, auto is not a "type" declaration, but a "placeholder" for type declaration. The compiler will replace auto with the actual variable type during compilation.

Rules for the use of auto

1. Auto is used in combination with pointers and references

Insert picture description here

2. Define multiple variables on the same line

void TestFun()
{
    
    
    auto a = 1,b = 2;
    auto c = 3,d = 4.0;//d = 4.0会出错,因为c和d的表达式类型不同
}

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 uses the deduced type to define other variables.

3. Scenes that auto cannot push

#include <iostream>
using namespace std;
void TestFun(auto a)
{
    
    }
void TestFun(auto a)//编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
{
    
    }

void TestAuto()
{
    
    
    int a[] = {
    
    1,2,3};
    //auto b[] = {4,5,6};//auto不能直接用来声明数组;
    auto c = a;//此处c的类型为int*
}

Guess you like

Origin blog.csdn.net/xhuyang111/article/details/114519469