In-depth understanding of inline function+auto+scope for+nullptr

Insert image description here

1. Inline functions

Calling a function requires establishing a stack frame. Registers must be saved in the stack frame and restored after completion. All of this is costly.

int add(int x, int y)
{
    
    
	int ret = x + y;
	return ret;
}

int main()
{
    
    
	add(2, 2);
	add(3, 2);
	add(4, 2);
	add(5, 2);
	add(1, 2);

	return 0;
}

However, for C language, macro optimization can be used for small functions that are frequently called.

Because the macro is replaced during the preprocessing stage, there is no execution overhead.

For the above add函数, using macros can look like this

#define ADD(x, y) ((x) + (y)) 

int main()
{
    
    
	cout << ADD(1, 2) << endl;
	cout << ADD(1, 2) << endl
	return 0;
}

But macros also have disadvantages:
1. They cannot be debugged
2. There is no type safety check
3. Some scenarios are very complex
and it is easy to make mistakes in the definition of macros.
It may be written like this accidentally #define ADD(x + y) x + y; = So when writing macros, errors are made, either Replacement error, either because of priority error

Therefore, inline functions are introduced in C++

1. Definition of inline functions

Inline functions insert the code of the function into the call point at compile time instead of executing it through function calls, which can reduce the overhead of function calls.

Inline functions are usually suitable for situations where the function body is small and frequently called, but not suitable for recursive functions or when the function body is large.

Use the inline keyword to declare a function as inline

内联函数的地址不会进入符号表

To be precise, inline functions have no addresses.

2. Declaration and definition of inline functions

#include <iostream>
using namespace std;
// 定义一个内联函数
inline int add(int a, int b) {
    
    
    return a + b;
}

int main() {
    
    
    int x = 5;
    int y = 3;
    
    int result = add(x, y);
    
   cout << "Result: " << result << endl;
    
    return 0;
}

3. Features

  1. inlineIt is an optimization strategy of “exchanging space for time”. It recommends that the compiler expand functions into inline functions and replace function calls with function bodies during the compilation phase to reduce function call overhead and improve program running efficiency.

  2. Compiler pairing is inlineonly a suggestion and implementation may vary from compiler to compiler. Different compilers may use different strategies to decide which functions should be expanded into inline functions.

  3. inlineThere are advantages and disadvantages to using decorated functions. The advantage is that it can reduce function call overhead and improve program execution efficiency. The disadvantage is that the object file may become larger because the function is expanded at each call site. Therefore, it is necessary to weigh whether to use inlinethe choice based on the specific situation.
    Insert image description here
    4. inlineIt is not recommended to separate declarations and definitions, as separation will cause link errors. Because inline is expanded, there is no function address and the link will not be found.

4. Points to note about inline functions

  1. It is usually better to put the definition and declaration together for inline functions, because inline functions have no address. If there is only a declaration but no definition, the definition will not be found when calling the inline function and an error will occur, so应该在头文件中同时包含内联函数的声明和定义
  2. If the declaration of an inline function is placed in a header file and the definition is placed in other source files, the definition may not be found when the inline function is called, resulting in a compilation error.
  3. Whether inline functions are expanded at the call site is determined by the compiler. Even if a function is declared inline, there is no guarantee that it will be expanded. The compiler will optimize based on the complexity of the function body, call frequency and other factors, and decide whether to expand the inline function.
  4. The expansion of inline functions is related to compiler decisions. We can use inlinethe keyword to suggest that the compiler expand functions into inline functions, but the actual decision-making power rests with the compiler.

Conclusion: Short, frequently called small functions are recommended to be defined inline.

2. Scope for

The range for loop is a new loop syntax introduced in C++11 to simplify traversal operations on iterable objects such as containers and arrays. It provides a more concise and readable way to iteratively access elements.

1. Basic grammar

The basic syntax of a range for loop is as follows:

for (auto element : iterable) {
    
    
    // 循环体
}

Among them, elementis a copy of the current element during the iteration process, iterablewhich is an iterable object, such as a container or array.

2. Traverse the container

Range for loop can easily traverse various containers, such as vector, listetc. We no longer need to use iterators or indexes to traverse, but directly use a range for loop:

vector<int> nums = {
    
    1, 2, 3, 4, 5};

for (auto num : nums) {
    
    
    cout << num << " ";
}

// 输出:1 2 3 4 5

3. const and reference

By using constkeywords, range for loops can also implement read-only traversal, protecting the data in the container from being modified:

vector<int> nums = {
    
    1, 2, 3, 4, 5};

for (const auto& num : nums) {
    
    
    cout << num << " ";
}

// 输出:1 2 3 4 5

In the above code, numit is declared as const auto&, indicating read-only access to the elements in the container.

4. Array traversal

Range for loops are also suitable for array traversal, making the code more concise:

int arr[] = {
    
    1, 2, 3, 4, 5};

for (auto e : arr) {
    
    
    cout << e << " ";
}

// 输出:1 2 3 4 5

5. Custom type traversal

For custom types, you only need to provide overloads begin()of end()member functions or non-member functions, and you can use a range for loop to traverse. For example:

class MyContainer {
    
    
public:
    int* begin()
    {
    
     
    return &data[0];
    }
    int* end() 
    {
    
     
    return &data[size]; 
    }

private:
    int data[5] = {
    
    1, 2, 3, 4, 5};
};

MyContainer container;

for (auto e : container) {
    
    
    cout << e << " ";
}

// 输出:1 2 3 4 5

In the above code, MyContainerthe class provides begin()and end()functions so that the object can be traversed using a range for loop like a container.

The range for loop is a powerful and concise feature in C++, which can greatly simplify the code for iterative operations and improve the readability of the code.

6. Conditions of use

The range of for loop iteration must be certain

The range of an array is the range of the first element and the last element in the array;

For classes, begin and end methods should be provided. Begin and end are the scope of the for loop iteration.

When the function passes parameters, the array will degenerate into a pointer.

#include<iostream>
using namespace std;
void TestFor(int array[])
{
    
    
    for (auto& e : array)
    {
    
    
        cout << e << endl;
    }
}

int main()
{
    
    
	return 0;
}

Insert image description here

3. auto keyword

1. Automatic type inference

Use the auto keyword to automatically infer the type of a variable without explicitly specifying the type. The compiler infers the type of a variable based on its initialization expression.

auto num = 10; // 推断num的类型为int
auto name = "John"; // 推断name的类型为const char*
auto prices = {
    
     1.99, 3.49, 2.99 }; // 推断prices的类型为std::initializer_list<double>

Using the auto keyword can simplify the code, reduce repeated writing of types, and improve the readability of the code.

typeidYou can see the object type, the usage is typeid(c).name(), from which you can print the type of the variableInsert image description here

2. Function return value type inference

Using the auto keyword allows the compiler to infer the return value type of a function. This is particularly useful for functions that return complex types or involve generic programming.

auto add(int a, int b) {
    
    
    return a + b;
}

auto compute() {
    
    
    // 复杂类型的计算逻辑
    return result;
}

Here, the compiler will infer the return value type of functions add and compute based on the actual returned value.
Insert image description here

4.auto attention

1.auto cannot be defined independently
Insert image description here

2.auto cannot define an array
Insert image description here

3.auto cannot accept function parameters ,

Because the compiler cannot deduce the type of auto, there is no basis.

But in versions after C++11, auto can be used as a parameter
Insert image description here

4. nullptr (C++11)

For c, the null pointer is NULL and is a macro.

In C++98/03, only NULL can be used; after C++11, nullptr is recommended.

NULL(stddef.h):

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

In fact, NULL is a macro, so · 写成 int* p = 0·can also be said

But special circumstances

#include<iostream>
using namespace std;

void f(int a)
{
    
    
	cout << "f(int)" << endl;
}

void f(int* ptr)
{
    
    
	cout << "f(int*)" << endl;
}

int main()
{
    
    
	f(0);
	f(NULL);
	return 0;
}


Insert image description here

Replace NULL with nullptr
Insert image description here

5. Summary

This time, we mainly summarize the characteristics of inline functions, the use of the auto keyword, the use of range for, and the repair of nullptr.

Guess you like

Origin blog.csdn.net/2201_76062618/article/details/132012475