인라인 기능 사용시기와 사용하지 않을시기


185

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

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


11
inline무엇 C ++ 신인이다 CFLAGS젠투 신인에 있습니다 : 아니, 컴파일하는 것은 -O3 -funroll-loops -finline-functions기존의 펜티엄 비행하지 않습니다)
그레고리 Pakosz

1
인라인을 사용하지 않는 이유는 일부 디버거에서 중단 점을 설정하거나 인라인 된 함수로 단계를 설정할 수 없기 때문입니다.
Rob deFriesse 2009


5
함수를 인라인해야하는지 여부를 결정해서는 안됩니다. 컴파일러가 그렇게하도록하십시오. 그것은 당신보다 더 낫습니다 (그리고 각 호출의 환경에 따라 선택적으로 함수를 인라인 할 수 있습니다).
David Thornley

@DavidThornley 때로는 O3 플래그가 설정되어 있어도 정의가 cpp 파일에 있으면 컴파일러가 함수를 인라인하지 않습니다. 따라서 내가 따르는 엄지 규칙은 하나의 라이너와 루프가없는 함수를 인라인하는 것입니다.
talekeDskobeDa

답변:


209

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

하다:

  • 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에 의해 정의 된 인라인 함수에 대한 다른 규칙은 여전히 ​​준수되어야합니다.


34
inline컴파일러에 대한 힌트 이상입니다. 여러 정의에 대한 언어 규칙을 변경합니다. 또한 정적 데이터를 갖는 것이 함수 인라인을 피하는 주된 이유가 아닙니다. 구현은 함수 선언 여부에 상관없이 각 함수 정적에 대해 단일 정적 오브젝트를 할당해야합니다 inline. 인라인 생성자와 가상 소멸자가있는 클래스는 여전히 확장 가능합니다. 빈 괄호 소멸자는 때로는 인라인으로 두는 것이 좋습니다.
CB Bailey

2
그것은 함수가 반드시 인라인으로 끝나지 않는다는 의미에서 힌트입니다 (그러나 영어는 모국어가 아닙니다). 로 표시된 함수의 스태틱에 inline대한 결과는 함수가 인라인되지 않는다는 것입니다. 호출에 대한 가격을 지불하고 함수를 포함하고 호출하는 각 변환 단위는 자체 코드 및 정적 변수 사본을 가져옵니다. 라이브러리를 개발할 때 생성자와 소멸자를 인라이닝하지 않는 이유는 라이브러리의 향후 버전과 바이너리 호환성입니다.
Gregory Pakosz

14
"컴파일러에 대한 힌트"라고 부르는 것은 부정확합니다. 실제로 inline컴파일러가 그렇게 느끼면 비 기능을 인라인 할 수 있습니다. 그리고 inline컴파일러가 인라인하지 않기로 결정하면 함수가 인라인되지 않습니다. Charles Bailey가 말했듯이 언어 규칙이 변경됩니다. 최적화 힌트로 생각하기보다는 완전히 다른 개념으로 생각하는 것이 더 정확합니다. inline키워드는 여러 정의를 허용하는 컴파일러, 그리고 아무것도를 알려줍니다. "인라인"최적화는 표시 여부에 관계없이 거의 모든 기능에 적용 할 수 있습니다 inline.
jalf

26
Stroustrup이 "인라인 지정자가 컴파일러에 대한 힌트"라고 썼을 때, 나는 그를 인용 한 것에 대해 비난받는 것에 놀랐습니다. 어쨌든, 나는 가능한 한 많이 참조로하여이 대답을 백업하기 위해 최선을하고 충분한 시간을 보냈다
그레고리 Pakosz에게

2
@GregoryPakosz : 그러나 inline함수 인라인을 얻기 위해 모든 것을 사용하는 것은 아닙니다 . 때때로 우리는 ODR을 이용하는 것과 같은 다른 혜택을 원합니다.
궤도에서 가벼움 레이스

57

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

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

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


나는 이것이 C ++의 의도적 기능보다 행복한 우연의 일치라는 느낌을받습니다. 이 아이디어는 C의 '정적'전역 변수와 매우 유사하지만 매우 흥미로운 답변입니다. 내부 링크를 나타내는 데 'internal'과 같은 키워드를 사용했으면합니다.
Rehno Lindeque

+1. @Rehno : 당신이 무슨 말을하는지 잘 모르겠습니다. inline키워드 와 연계는 어떤 관계가 있습니까? 그리고 행복한 우연의 일치는 무엇입니까?
jalf

@ jalf : 회고에서 내 의견을 읽는 것은 그것이 모호하고 잘 생각되지 않는다는 것을 알고 있습니다. 여러 파일에서 동일한 함수를 정의하면 '정적'함수를 선언하여 링커 오류를 해결할 수 있습니다. 그러나 '인라인'을 사용하면 실제로 '정적'과 같은 내부 연결을 얻지 못하는 미묘한 차이로 동일한 작업을 수행 할 수 있습니다. 언어 구현 자 / 디자이너가 헤더 파일에 선언 된 함수를 사용하여 특수한 작업을 수행해야하고 '인라인'으로 넘어가는 것을 인식했기 때문에 이것이 실제로 더 우연의 일치라고 생각합니다.
Rehno Lindeque 2009

4
퍼포먼스가 인라인을 사용하는 주된 이유이기 때문에 귀하의 의견이 왜 그렇게 많은 표를 얻었는지 확실하지 않습니다.
gast128

10

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

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

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


실제로 특정 컴파일러가 '인라인'을 완전히 무시하고 '__inline'또는 '__force_inline'에만 응답한다는 의혹이 있습니다. 나는 이것이 학대를 저지하는 것이라고 생각합니다!
Rehno Lindeque 08

일반적으로 그렇지 않습니다. 인라인은 힌트 일 뿐이지 만 대부분의 컴파일러가 심각하게 생각하는 힌트입니다. 컴파일러가 객체 코드 ( /FAcsVisual Studio, -sGCC) 와 함께 어셈블리 언어를 내보내도록 설정하여 정확히 무엇을하는지 확인할 수 있습니다. 내 경험상 두 컴파일러 모두 인라인 키워드의 무게를 상당히 weigh니다.
Crashworks

1
내 경험상 g ++이나 VC는 inline키워드에 무게를 두지 않기 때문에 흥미 롭습니다 . 즉, 함수가 인라인되는 것을보고 inline지정자를 제거 하면 여전히 인라인됩니다. 반대의 구체적인 예가 있다면 공유하십시오!
Pavel Minaev

4
어떻게합니까 inline키워드을 방해 "명확한 코드를?" "조기 최적화"의 키워드는 조기 하지 최적화. 적극적으로 최적화를 피해야한다고 말하는 것은 쓰레기 일뿐입니다. 그 말의 요점은 필요하지 않은 최적화를 피하고 코드에 유해한 부작용 (예 : 유지 관리가 덜하도록)을 피해야한다는 것입니다. 나는 방법을 보려면 실패 inline키워드는 코드가 덜 유지 보수 만들려고, 또는 함수에 추가하는 해가 될 수있는 방법.
jalf

3
jalf, 때로는 함수를 인라인하면 코드가 느려지지 않고 빠르지 않습니다. 한 가지 예는 함수가 코드의 여러 곳에서 호출 된 경우입니다. 함수가 인라인되지 않은 경우 다른 위치에서 호출 될 때 명령 캐시에있을 수 있으며 분기 예측 변수가 이미 예열되었을 수 있습니다. 항상 효율성을 향상시키는 패턴이 있으므로 사용하는 데 아무런 문제가 없습니다. 인라인은 그중 하나가 아닙니다. 일반적으로 성능에 전혀 영향을 미치지 않으며 때로는 도움이되고 때로는 상처를줍니다. 나는 나의 조언 뒤에 서있다 : 먼저 프로파일을 한 다음, 인라인.
dmazzoni 2009

5

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

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


4

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

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

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

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


2

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

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


1

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

void IncreaseCount() { freeInstancesCnt++; }

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


0

나는 일반적으로 3-4 개의 간단한 문장으로 인라인으로 함수를 만드는 엄지 손가락 규칙을 따릅니다. 그러나 컴파일러에 대한 힌트 일뿐입니다. 인라인인지 아닌지에 대한 마지막 호출은 컴파일러에서만 수행됩니다. 이 많은 문장이 많으면 어리석은 컴파일러와 마찬가지로 인라인으로 선언하지 않으므로 코드가 팽창 될 수 있습니다.


0

가장 좋은 방법은 인라인 및 인라인되지 않은 생성 된 명령어를 검사하고 비교하는 것입니다. 그러나 항상 생략하는 것이 안전합니다 inline. 사용하면 inline원하지 않는 문제가 발생할 수 있습니다.


0

인라인 사용 여부를 결정할 때는 일반적으로 다음과 같은 아이디어를 염두에 두어야합니다. 최신 머신에서는 메모리 대기 시간이 원시 계산보다 병목 현상이 클 수 있습니다. 종종 호출되는 인라인 함수는 실행 파일 크기를 늘리는 것으로 알려져 있습니다. 또한 이러한 기능을 CPU의 코드 캐시에 저장하면 해당 코드에 액세스해야 할 때 캐시 누락 수를 줄일 수 있습니다.

따라서 인라인은 생성 된 기계어 코드의 크기를 늘리거나 줄입니까? 함수를 호출하면 캐시 미스가 발생할 가능성은 얼마나됩니까? 코드 전체에 후추가 뿌려지면 가능성이 높다고 말할 것입니다. 단일 타이트 루프로 제한되면 가능성이 낮을 것입니다.

나는 일반적으로 다음과 같은 경우에 인라인을 사용합니다. 그러나 성능에 대해 정말로 우려하는 경우 프로파일 링이 필수적입니다. 또한 컴파일러가 실제로 힌트를 취하는 지 확인하고 싶을 수도 있습니다.

  • 긴밀한 루프에서 호출되는 짧은 루틴.
  • 매우 기본적인 접근 자 (get / set)와 래퍼 함수.
  • 불행히도 헤더 파일의 템플릿 코드는 자동으로 인라인 힌트를 얻습니다.
  • 매크로처럼 사용되는 짧은 코드입니다. (예 : min () / max ())
  • 짧은 수학 루틴.

0

또한 인라인 방법은 대규모 프로젝트를 유지 관리 할 때 심각한 부작용이 있습니다. 인라인 코드가 변경되면 해당 코드를 사용하는 모든 파일이 컴파일러에 의해 자동으로 다시 작성됩니다 (좋은 컴파일러입니다). 개발 시간이 많이 소요될 수 있습니다.

inline방법은 소스 파일로 전송하고 더 이상 인라인되지 않고, 전체 프로젝트는 (적어도이 내 경험이었다) 다시 작성해야합니다. 또한 메소드가 인라인으로 변환되는 경우.


1
그것은 다른 문제입니다. 헤더 파일에있는 코드에 대한 재 구축 문제가 발생합니다. 표시 여부와 inline상관없이 ( 키워드가없는 경우 inline제외) 링커 오류가 발생하지만 inline키워드가 과도한 재 구축을 유발하는 문제는 아닙니다.
jalf

그러나 인라인 메소드를 변경하면 shource 파일에서 비 인라인 메소드를 변경하는 것과 비교하여 과도한 빌드가 발생합니다.
Thomas Matthews

0

하나는 사용해야 인라인 함수 코드 기능이 메모리 공간의 절약 가치 실행 속도의 비교적 작은 희생 때문에 당신이 정상적인 기능을 선호한다 큰 small.If 경우에만 기능 한정자를.


0

코드가 인라인으로 사용하기에 충분히 작고 인라인 함수를 기억하고 코드를 복사하여 붙여 넣는 것을 기억할 때 함수가 호출되었으므로 실행 시간을 늘리기에는 충분하지만 메모리 소비도 증가 할 수 있습니다. 루프 / 정적 변수 / 재귀 / 스위치 / 고토 / 가상 함수를 사용하는 경우 인라인 함수를 사용할 수 없습니다. 가상은 컴파일하는 동안 런타임과 인라인을 기다릴 수 있으므로 동시에 사용할 수 없습니다.


-2

나는 몇 가지 답변을 읽었으며 누락 된 것들이 있음을 알았습니다.

내가 사용하는 규칙은 인라인이 아닌 한 인라인을 사용하지 않는 것입니다. 어리석은 표정 이네요.

컴파일러는 충분히 똑똑하고 짧은 기능은 항상 인라인을 만듭니다. 프로그래머가 그렇게 말하지 않는 한 긴 기능을 인라인으로 만들지 마십시오.

인라인이 힌트 또는 컴파일러 요청이라는 것을 알고 있습니다.

실제로 inline컴파일러의 순서이며 선택의 여지가 없으며 after inline키워드는 모든 코드를 인라인으로 만듭니다. 그래서 당신은 결코 사용할 수 없습니다inline 키워드를 컴파일러는 가장 짧은 코드를 설계합니다.

그래서 언제 사용 inline 합니까?

코드를 인라인으로 사용하려는 경우에 사용합니다. 한 가지 상황에서만 사용하기 때문에 한 가지 예만 알고 있습니다. 사용자 인증입니다.

예를 들어이 기능이 있습니다.

inline bool ValidUser(const std::string& username, const std::string& password)
{
    //here it is quite long function
}

이 기능이 아무리 커도 소프트웨어를 크랙하기 어렵 기 때문에 인라인으로 만들고 싶습니다.


2
인라인은 여전히 ​​힌트입니다. 함수가 부풀어 오른 것으로 간주되면 컴파일러가 인라인하지 못할 수 있습니다.
It'sPete

하나는 인라인이 명령이라고 말하고 다른 하나는 힌트를 말합니다.

@ user2918461 나는 인라인 문장을 지원합니다. 이것은 많은 웹 사이트와 서적에서 지원되었습니다
WARhead
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.