인라인 함수+자동+범위+nullptr에 대한 심층적인 이해

여기에 이미지 설명을 삽입하세요.

1. 인라인 함수

함수를 호출하려면 스택 프레임을 설정해야 하며 레지스터를 스택 프레임에 저장하고 완료 후 복원해야 하는데 이 모든 작업에는 비용이 많이 듭니다.

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;
}

그러나 C 언어의 경우 자주 호출되는 작은 함수에 대해서는 매크로 최적화를 사용할 수 있습니다.

전처리 단계에서 매크로가 교체되므로 실행 오버헤드가 없습니다.

위의 경우 add函数매크로를 사용하면 다음과 같습니다.

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

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

그러나 매크로에도 단점이 있습니다:
1. 디버깅할 수 없습니다
. 2. 유형 안전성 검사가 없습니다
. 3. 일부 시나리오는 매우 복잡
하고 매크로 정의에서 실수를 저지르기 쉽습니다.
실수로 이렇게 작성될 수 있습니다 #define ADD(x + y) x + y. ; = 그래서 매크로를 작성할 때 오류가 발생합니다. 대체 오류이거나 우선 순위 오류로 인해 발생합니다.

따라서 C++에는 인라인 함수가 도입되었습니다.

1. 인라인 함수의 정의

인라인 함수는 함수 호출을 통해 함수를 실행하는 대신 컴파일 타임에 함수 코드를 호출 지점에 삽입하므로 함수 호출의 오버헤드를 줄일 수 있습니다.

인라인 함수는 일반적으로 함수 본문이 작고 자주 호출되는 상황에 적합하지만 재귀 함수나 함수 본문이 큰 경우에는 적합하지 않습니다.

inline 키워드를 사용하여 함수를 인라인으로 선언

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

정확하게 말하면 인라인 함수에는 주소가 없습니다.

2. 인라인 함수 선언 및 정의

#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. 특징

  1. inline공간을 시간으로 바꾸는 최적화 전략이다. 컴파일러는 함수 호출 오버헤드를 줄이고 프로그램 실행 효율성을 높이기 위해 컴파일 단계에서 함수를 인라인 함수로 확장하고 함수 호출을 함수 본문으로 대체할 것을 권장합니다.

  2. 컴파일러 쌍은 inline제안일 뿐이며 구현은 컴파일러마다 다를 수 있습니다. 컴파일러마다 다른 전략을 사용하여 어떤 함수를 인라인 함수로 확장해야 하는지 결정할 수 있습니다.

  3. 데코레이팅된 함수를 사용하면 inline장점과 단점이 있습니다 . 함수 호출 오버헤드를 줄이고 프로그램 실행 효율성을 높일 수 있다는 장점이 있습니다. 단점은 각 호출 사이트에서 기능이 확장되기 때문에 개체 파일이 커질 수 있다는 점입니다. 따라서 inline구체적인 상황에 따라 선택을 사용할지 여부를 저울질할 필요가 있다.
    여기에 이미지 설명을 삽입하세요.
    4. inline선언과 정의를 분리하는 것은 권장되지 않습니다. 분리하면 링크 오류가 발생하기 때문입니다. 인라인이 확장되었기 때문에 함수 주소가 없고 링크도 찾을 수 없습니다.

4. 인라인 함수 주의사항

  1. 일반적으로 인라인 함수의 경우 정의와 선언을 함께 두는 것이 더 좋은데, 인라인 함수에는 주소가 없기 때문입니다. 선언만 있고 정의가 없으면 인라인 함수를 호출할 때 정의를 찾을 수 없으므로 오류가 발생합니다.应该在头文件中同时包含内联函数的声明和定义
  2. 인라인 함수의 선언이 헤더 파일에 있고 정의가 다른 소스 파일에 있는 경우 인라인 함수를 호출할 때 정의를 찾지 못해 컴파일 오류가 발생할 수 있습니다.
  3. 인라인 함수가 호출 사이트에서 확장되는지 여부는 컴파일러에 의해 결정됩니다. 함수가 인라인으로 선언되더라도 확장된다는 보장은 없습니다. 컴파일러는 함수 본문의 복잡성, 호출 빈도 및 기타 요소를 기반으로 최적화하고 인라인 함수를 확장할지 여부를 결정합니다.
  4. 인라인 함수의 확장은 컴파일러 결정과 관련이 있습니다. inline키워드를 사용하여 컴파일러가 함수를 인라인 함수로 확장하도록 제안할 수 있지만 실제 의사 결정 권한은 컴파일러에 있습니다.

결론: 짧고 자주 호출되는 작은 함수는 인라인으로 정의하는 것이 좋습니다.

2. 범위

for 루프 범위는 컨테이너 및 배열과 같은 반복 가능한 객체에 대한 순회 작업을 단순화하기 위해 C++11에 도입된 새로운 루프 구문입니다. 요소에 반복적으로 액세스하는 보다 간결하고 읽기 쉬운 방법을 제공합니다.

1. 기본 문법

범위 for 루프의 기본 구문은 다음과 같습니다.

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

그중에는 element반복 프로세스 중 현재 요소의 복사본이 있는데, iterable이는 컨테이너나 배열과 같은 반복 가능한 객체입니다.

2. 컨테이너 탐색

Range for 루프는 등 의 다양한 컨테이너를 쉽게 순회할 수 있습니다 vector. list더 이상 순회하기 위해 반복자나 인덱스를 사용할 필요가 없지만 for 루프 범위를 직접 사용합니다.

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

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

// 输出:1 2 3 4 5

3. const 및 참조

키워드를 사용하면 constrange for 루프가 읽기 전용 순회를 구현하여 컨테이너의 데이터가 수정되지 않도록 보호할 수도 있습니다.

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

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

// 输出:1 2 3 4 5

위 코드에서는 num로 선언되어 const auto&컨테이너의 요소에 대한 읽기 전용 액세스를 나타냅니다.

4. 배열 순회

Range for 루프는 배열 순회에도 적합하므로 코드가 더욱 간결해집니다.

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

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

// 输出:1 2 3 4 5

5. 사용자 정의 유형 순회

사용자 정의 유형의 경우 멤버 함수 또는 비멤버 함수 begin()의 오버로드 만 제공하면 되며 범위 for 루프를 사용하여 순회할 수 있습니다. end()예를 들어:

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

위 코드에서 MyContainer클래스는 컨테이너처럼 for 루프를 이용해 객체를 순회할 수 있도록 제공 begin()하고 기능한다.end()

for 루프의 범위는 C++의 강력하고 간결한 기능으로, 반복 작업을 위한 코드를 크게 단순화하고 코드의 가독성을 향상시킬 수 있습니다.

6. 이용조건

for 루프 반복 범위는 확실해야 합니다.

배열의 범위는 배열의 첫 번째 요소와 마지막 요소의 범위입니다.

클래스의 경우 start 및 end 메소드를 제공해야 하며 Begin 및 end는 for 루프 반복의 범위입니다.

함수가 매개변수를 전달하면 배열은 포인터로 변질됩니다.

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

int main()
{
    
    
	return 0;
}

여기에 이미지 설명을 삽입하세요.

3. 자동 키워드

1. 자동 유형 추론

유형을 명시적으로 지정하지 않고 변수 유형을 자동으로 추론하려면 auto 키워드를 사용하십시오. 컴파일러는 초기화 표현식을 기반으로 변수의 유형을 유추합니다.

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

auto 키워드를 사용하면 코드가 단순화되고, 유형을 반복적으로 작성하는 일이 줄어들며, 코드의 가독성이 향상됩니다.

typeid객체 유형(사용법)을 볼 수 있으며 typeid(c).name(), 여기에서 변수 유형을 인쇄할 수 있습니다.여기에 이미지 설명을 삽입하세요.

2. 함수 반환값 유형 추론

auto 키워드를 사용하면 컴파일러가 함수의 반환 값 유형을 유추할 수 있습니다. 이는 복잡한 유형을 반환하거나 일반 프로그래밍을 포함하는 함수에 특히 유용합니다.

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

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

여기서 컴파일러는 실제 반환된 값을 기반으로 함수 add 및 계산의 반환 값 유형을 추론합니다.
여기에 이미지 설명을 삽입하세요.

4. 자동주의

1.auto는 독립적으로 정의할 수 없습니다.
여기에 이미지 설명을 삽입하세요.

2.auto는 배열을 정의할 수 없습니다.
여기에 이미지 설명을 삽입하세요.

3.auto는 기능 매개변수를 받아들일 수 없습니다 .

컴파일러는 auto 유형을 추론할 수 없으므로 근거가 없습니다.

하지만 C++11 이후 버전에서는 auto를 매개변수로 사용할 수 있습니다.
여기에 이미지 설명을 삽입하세요.

4. 널포인트(C++11)

c의 경우 널 포인터는 NULL이며 매크로입니다.

C++98/03에서는 NULL만 사용할 수 있으며, C++11 이후에는 nullptr을 권장합니다.

NULL(stddef.h):

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

사실 NULL은 매크로이므로 · 写成 int* p = 0·라고도 할 수 있습니다 .

하지만 특별한 상황

#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;
}


여기에 이미지 설명을 삽입하세요.

NULL을 nullptr로 대체
여기에 이미지 설명을 삽입하세요.

5. 요약

이번에는 인라인 함수의 특징, auto 키워드의 활용, range for의 활용, nullptr의 Repair 등을 주로 정리하였습니다.

추천

출처blog.csdn.net/2201_76062618/article/details/132012475