[c++] 인라인 기능 사용시기와 사용하지 않을시기

인라인은 컴파일러에 대한 힌트 또는 요청이며 함수 호출 오버 헤드를 피하는 데 사용됩니다.

따라서 함수가 인라인 후보인지 여부를 어떤 기준으로 결정할 수 있습니까? 어떤 경우에는 인라인을 피해야합니까?



답변

함수 호출 비용을 피하는 것은 이야기의 절반에 지나지 않습니다.

하다:

  • inline대신에 사용#define
  • 매우 작은 기능은 inline더 빠른 코드와 더 작은 실행 파일에 적합합니다 (코드 캐시에 더 많은 기회가있을 수 있음)
  • 함수는 작고 매우 자주 호출

하지 마십시오 :

  • 큰 기능 : 더 큰 실행 파일로 이어 지므로 호출 오버 헤드로 인한 빠른 실행에 관계없이 성능이 크게 저하됩니다.
  • I / O 바인딩 된 인라인 함수
  • 이 기능은 거의 사용되지 않습니다
  • 생성자와 소멸자 : 비어 있어도 컴파일러는 코드를 생성합니다
  • 라이브러리 개발시 바이너리 호환성 깨기 :
    • 기존 함수를 인라인
    • 인라인 함수를 변경하거나 인라인 함수를 비 인라인으로 만들기 : 라이브러리의 이전 버전은 이전 구현을 호출합니다.

라이브러리를 개발할 때 미래에 클래스를 확장 가능하게하려면 다음을 수행해야합니다.

  • 본문이 비어 있어도 인라인이 아닌 가상 소멸자를 추가
  • 모든 생성자를 비 인라인으로 만들기
  • 클래스를 값으로 복사 할 수없는 경우가 아니라면 복사 생성자와 할당 연산자의 비 인라인 구현을 작성하십시오.

inline키워드는 컴파일러에 대한 힌트 임을 기억하십시오 . 컴파일러는 함수를 인라인하지 않기로 결정할 수 inline있으며 처음 에는 표시되지 않은 함수를 인라인하기로 결정할 수 있습니다 . 나는 일반적으로 기능을 표시하지 않습니다 inline(아마도 매우 작은 기능을 작성할 때).

성능과 관련하여 현명한 접근 방식은 항상 응용 프로그램을 프로파일 링 한 다음 inline병목 현상을 나타내는 일련의 기능입니다.

참고 문헌 :


편집 : Bjarne Stroustrup, C ++ 프로그래밍 언어 :

함수는로 정의 될 수 있습니다 inline. 예를 들면 다음과 같습니다.

inline int fac(int n)
{
  return (n < 2) ? 1 : n * fac(n-1);
}

inline지정은의 호출 코드를 생성하려고 시도한다는 것을 컴파일러에 대한 힌트 fac()번 기능에 대한 코드를 내려 놓고 다음 일반적인 함수 호출 메커니즘을 통해 호출하는 것보다 인라인이 아니라. 영리한 컴파일러는 720호출에 대한 상수 를 생성 할 수 있습니다 fac(6). 상호 재귀적인 인라인 함수, 입력에 따라 반복되는 인라인 함수 등의 가능성으로 인해 inline함수 의 모든 호출 이 실제로 인라인 되도록 보장 할 수 없습니다 . 컴파일러의 영리한 정도는 법제화 될 수 없으므로 한 컴파일러는 720또 다른 컴파일러는 또 다른 컴파일러는 6 * fac(5)인라인되지 않은 호출을 생성 할 수 있습니다 fac(6).

비정상적으로 영리한 컴파일 및 연결 기능이없는 상태에서 인라인을 가능하게하려면 인라인 함수의 선언뿐만 아니라 정의도 범위 내에 있어야합니다 (§9.2). inlineespecifier은 함수의 의미에 영향을주지 않습니다. 특히 인라인 함수에는 여전히 고유 한 주소가 있으므로 static인라인 함수의 변수 (§7.1.2)가 있습니다.

EDIT2 : ISO-IEC 14882-1998, 7.1.2 기능 지정자

지정자가있는 함수 선언 (8.3.5, 9.3, 11.4) inline은 인라인 함수를 선언합니다. 인라인 지정자는 호출 시점에서 함수 본문의 인라인 대체가 일반적인 함수 호출 메커니즘보다 선호됨을 구현에 표시합니다. 호출 시점에서이 인라인 대체를 수행하기 위해 구현이 필요하지 않습니다. 그러나이 인라인 대체가 생략 되더라도 7.1.2에 의해 정의 된 인라인 함수에 대한 다른 규칙은 여전히 ​​준수되어야합니다.


답변

inline최적화와 관련이 거의 없습니다. inline주어진 정의 된 함수가 프로그램에서 여러 번 발생하는 경우 오류가 발생하지 않도록 컴파일러에 지시하는 명령이며, 사용되는 모든 번역에서 정의가 발생하고 모든 곳에서 정의가 정확히 동일한 정의를 가질 것이라고 약속합니다.

위의 규칙이 주어지면 inline선언에 필요한 것에 대한 추가 종속성을 포함하여 본문이 필요하지 않은 짧은 함수에 적합합니다. 정의가 발생할 때마다 구문 분석되어야하고 본문에 대한 코드가 생성 될 수 있으므로 단일 소스 파일에서 한 번만 정의 된 함수에 대한 일부 컴파일러 오버 헤드를 의미합니다.

컴파일러는 선택한 함수 호출을 인라인 (즉, 함수 호출을 해당 함수의 해당 동작을 수행하는 코드로 대체) 할 수 있습니다. 예전에는 호출과 동일한 변환 단위로 선언되지 않은 함수를 “명확하게”인라인 할 수 없었지만 링크 시간 최적화 사용이 증가함에 따라 지금도 사실이 아닙니다. 마킹 된 함수 inline가 인라인되지 않을 수도 있다는 사실도 마찬가지입니다 .


답변

컴파일러에게 함수를 인라인하도록하는 것은 최적화이며, 최적화의 가장 중요한 규칙은 조기 최적화가 모든 악의 근원이라는 것입니다. 효율적인 알고리즘을 사용하여 항상 명확한 코드를 작성한 다음 프로그램을 프로파일 링하고 너무 오래 걸리는 기능 만 최적화하십시오.

특정 함수가 매우 짧고 단순하다는 것을 알고 내부 꽉 조여진 루프에서 수만 번 호출되면 좋은 후보가 될 수 있습니다.

그러나 많은 C ++ 컴파일러가 자동으로 작은 함수를 인라인하고 인라인 요청을 무시할 수도 있습니다.


답변

알아내는 가장 좋은 방법은 프로그램을 프로파일 링하고 여러 번 호출되는 작은 기능을 표시하고 CPU 사이클을 통해 레코딩하는 것입니다. inline 입니다. 여기서 키워드는 “작은”입니다. 일단 함수 호출 오버 헤드가 함수에 소요 된 시간과 비교할 때 무시할 만하면 인라인으로 표시 할 수 없습니다.

내가 제안하는 다른 용도는 캐시 누락과 관련이있을 정도로 성능이 중요한 코드에서 자주 호출되는 작은 함수가있는 경우 인라인해야한다는 것입니다. 다시, 그것은 프로파일 러가 당신에게 말할 수있는 것입니다.


답변

조기 최적화는 모든 악의 근원입니다!

경험상 일반적으로 “getters”와 “setters”만 인라인합니다. 코드가 작동하고 안정되면 프로파일 링은 어떤 함수가 인라인으로 혜택을 볼 수 있는지 보여줄 수 있습니다.

다른 한편으로, 대부분의 최신 컴파일러는 꽤 좋은 최적화 알고리즘을 가지고 있으며 인라인해야 할 내용을 인라인합니다.

재개-인라인 원 라이너 기능을 작성하고 나중에 다른 것에 대해 걱정하십시오.


답변

인라인 함수의 인수를 스택으로 푸시 할 필요가 없어 코드 성능을 향상시킬 수 있습니다. 문제의 함수가 코드의 중요한 부분에있는 경우 프로젝트의 최적화 부분에서 인라인이 아닌 인라인 결정을 내려야합니다.

C ++ FAQ 에서 인라인에 대해 자세히 읽을 수 있습니다.


답변

종종 인라인 함수를 최적화로 사용하지 않고 코드를 더 읽기 쉽게 만듭니다. 때로는 코드 자체가 주석, 설명이 포함 된 이름보다 짧고 이해하기 쉽습니다. 예를 들면 다음과 같습니다.

void IncreaseCount() { freeInstancesCnt++; }

독자는 코드의 완전한 의미를 즉시 알 수 있습니다.