C ++에서 인라인 함수의 이점은 무엇입니까?


254

C ++에서 인라인 함수를 사용할 때의 장점 / 단점은 무엇입니까? 컴파일러가 출력하는 코드의 성능 만 향상 시키지만 오늘날 최적화 된 컴파일러, 빠른 CPU, 대용량 메모리 등 (메모리가 부족하고 모든 것이 100KB의 메모리에 적합해야했던 1980 년과는 다른) 그들은 오늘날 실제로 장점이 있습니까?


48
이것은 일반적인 지식이 잘못된 질문 중 하나입니다. 모두 표준 Comp Sci 답변으로 답변했습니다. 인라인은 함수 호출 비용을 절약하지만 코드 크기를 증가시킵니다. 쓰레기. 컴파일러가 더 많은 최적화를 적용 할 수있는 간단한 메커니즘을 제공합니다.
Martin York

37
이것은 의견으로 제시되는 답변 중 하나입니다. 게시 된 답변이 마음에 들지 않으면 자신의 답변을 게시하고 어떻게 진행되는지 확인하십시오.
Dave Van den Eynde

10
이 질문의 기초에는 결함이 있습니다. C ++ 인라인 함수는 컴파일하는 동안 컴파일러 인라이닝과 거의 관련이 없습니다. 불행히도 inlinec ++ 키워드이며 인라인은 컴파일러 최적화 기술입니다. 정답을 보려면 " 언제 inline함수 / 방법에 대한 키워드 를 작성해야하는 경우 "라는 질문을 참조하십시오 .
deft_code

3
@JoseVega 링크가 엉망이 되었습니다

답변:


143

인라인 함수는 매개 변수 및 반환 주소와 같이 스택에서 물건을 밀거나 뺄 필요가 없으므로 더 빠릅니다. 그러나 바이너리를 약간 크게 만듭니다.

큰 차이가 있습니까? 최신 하드웨어에서는 눈에 띄게 충분하지 않습니다. 그러나 그것은 어떤 사람들에게는 충분한 차이를 만들 수 있습니다.

인라인으로 표시한다고해서 인라인 일 것이라는 보장은 없습니다. 컴파일러에 대한 제안 일뿐입니다. 때로는 가상 기능이 있거나 재귀가 관련된 경우와 같이 불가능할 수도 있습니다. 때로는 컴파일러가 사용하지 않기로 선택하기도합니다.

이와 같은 상황이 감지 가능한 차이를 만드는 것을 볼 수 있습니다.

inline int aplusb_pow2(int a, int b) {
  return (a + b)*(a + b) ;
}

for(int a = 0; a < 900000; ++a)
    for(int b = 0; b < 900000; ++b)
        aplusb_pow2(a, b);

26
인라인으로 의심되는 것처럼 위와 아무런 차이가 없습니다. gcc 4.01로 컴파일되었습니다. 버전 1 인라인 사용 강제 : 48.318u 1.042s 5 : 51.39 99.4 % 0 + 0k 0 + 0io 0pf + 0w 버전 2 강제 인라인 없음 348.311u 1.019s 5 : 52.31 99.1 % 0 + 0k 0 + 0io 0pf + 0w 이것은 좋은 예는 상식이 잘못되었다는 것입니다.
Martin York

36
호출 자체가 중요하지만 인라인을 사용하면 얻을 수있는 사소한 이익입니다. 주요 이점은 컴파일러가 포인터가 서로 별명을 표시하지 않는 위치, 호출자의 변수가 호출 수신자 등으로 끝나는 위치를 확인할 수 있다는 것입니다. 따라서 다음 최적화가 더 중요합니다.
Johannes Schaub-litb

31
함수의 결과가 사용되지 않거나 함수에 부작용이 없으므로이 스 니펫에는 차이가 없습니다. 이미지 처리에서 인라인으로 측정 할 수있는 성능이 향상되었습니다.
plinth

4
차이가없는 이유는 컴파일러가 자체적으로 인라인 할 수 있기 때문입니다. 또는 코드가 작으므로 코드 프리 페치 문제가 없습니다.
einpoklum

3
@einpoklum 컴파일러로 인해 전체 루프를 최적화했을 수도 있습니다.
noɥʇʎԀʎzɐɹƆ

197

장점

  • 필요한 곳에 코드를 인라인하면 프로그램이 함수 호출 및 리턴 파트에 더 적은 시간을 소비합니다. 커질수록 코드가 더 빨라집니다 (아래 참조). 사소한 접근자를 인라인하는 것이 효과적인 인라인의 예일 수 있습니다.
  • 인라인으로 표시하면 헤더 파일에 함수 정의를 넣을 수 있습니다 (예 : 링커가 불평하지 않고 여러 컴파일 단위에 포함될 수 있음).

단점

  • 코드를 더 크게 만들 수 있습니다 (즉, 사소한 기능에 인라인을 사용하는 경우). 따라서 페이징을 유발하고 컴파일러의 최적화를 무효화 할 수 있습니다.
  • 개체 처리 내부를 노출하기 때문에 캡슐화가 약간 손상됩니다 (그러나 모든 "개인"멤버도 마찬가지입니다). 즉, PImpl 패턴에서 인라인을 사용해서는 안됩니다.
  • 캡슐화가 약간 깨집니다. C ++ 인라이닝은 컴파일 타임에 해결됩니다. 즉, 인라인 함수의 코드를 변경 해야하는 경우 코드를 사용하여 모든 코드를 다시 컴파일해야 업데이트됩니다 (같은 이유로 함수 매개 변수의 기본값은 피함)
  • 헤더에 사용하면 헤더 파일이 더 커지므로 사용자가 신경 쓰지 않는 코드로 흥미로운 정보 (클래스 메소드 목록과 같은)를 희석합니다 (이것이 내부에서 인라인 함수를 선언하는 이유입니다. 클래스, 클래스 본문 뒤의 헤더에 정의하며 클래스 본문 내부에는 절대 정의하지 않습니다).

인라인 매직

  • 컴파일러는 인라인으로 표시 한 함수를 인라인하거나 인라인하지 않을 수 있습니다. 컴파일 또는 링크 타임에 인라인으로 표시되지 않은 인라인 함수를 결정할 수도 있습니다.
  • 인라인은 컴파일러에 의해 제어되는 복사 / 붙여 넣기와 같이 작동하며 전 처리기 매크로와는 매우 다릅니다. 매크로는 강제로 인라인되고 모든 네임 스페이스와 코드를 오염 시키며 쉽게 디버깅 할 수 없으며 심지어 수행 될 수도 있습니다. 컴파일러가 비효율적 인 것으로 판단했을 경우.
  • 클래스 자체에 정의 된 클래스의 모든 메소드는 "인라인 된"것으로 간주됩니다 (컴파일러가 여전히 인라인하지 않기로 결정할 수있는 경우에도)
  • 가상 메소드는 피할 수 없습니다. 여전히 컴파일러가 객체의 유형을 확실히 알 수있는 경우 (예 : 객체가 동일한 함수 본문 내에 선언 및 생성 된 경우) 컴파일러가 객체의 유형을 정확히 알고 있기 때문에 가상 함수도 인라인됩니다.
  • 템플릿 메서드 / 함수는 항상 인라인되지는 않습니다 (헤더에 존재하더라도 자동으로 인라인되지는 않습니다).
  • "인라인"다음 단계는 템플릿 메타 프로그래밍입니다. 즉, 컴파일 타임에 코드를 "인라인"하여 컴파일러가 함수의 최종 결과를 추론 할 수 있습니다. 따라서 복잡한 알고리즘을 때로는 일종의 return 42 ;문장 으로 줄일 수 있습니다 . 이것은 나를 위해 극단적 인라이닝 입니다. 실제로는 거의 발생하지 않으며 컴파일 시간이 길어지고 코드가 부풀어지지 않으며 코드가 빨라집니다. 그러나 성배처럼 대부분의 처리가 이런 식으로 해결할 수 없기 때문에 어디에서나 적용하려고하지 마십시오 ... 여전히 멋지다 ...
    :-p

캡슐화가 약간 손상된다고했습니다. 예를 사용하여 설명해 주시겠습니까?
소멸자

6
@PravasiMeet : C ++입니다. DLL / 공유 라이브러리를 클라이언트에 전달하면 클라이언트는이를 컴파일합니다. 멤버 변수 X를 사용하고 작업 Y를 수행하는 인라인 함수 foo는 클라이언트의 코드에 인라인됩니다. 멤버 변수를 Z로 변경 한 업데이트 된 버전의 DLL을 제공하고 Y 작업 외에도 YY 작업을 추가해야한다고 가정 해 봅시다. 클라이언트는 foo의 코드 때문에 DLL을 프로젝트 및 BOOM에 복사하기 만합니다. 이진 파일에는 업데이트 된 코드가 아닙니다. 클라이언트가 개인 코드에 대한 법적 액세스 권한이 없지만 인라이닝을 사용하면 "공개"상태가됩니다.
paercebal

@paercebal 두 번째에서 마지막 글 머리 기호와 관련하여 함수 템플릿이 인라인 이 아닌 예를들 수 있습니까? 나는 그들이 편리한 참조를 가지고 있지는 않지만 항상 인라인이라고 생각했다 (단순한 테스트는 그것을 확인하는 것처럼 보인다).
Konrad Rudolph

@KonradRudolph n4594에서 다음을 참조하십시오 3.2/6: There can be more than one definition of [..] inline function with external linkage [..] non-static function template.. 5.1.5 / 6에서 For a generic lambda, the closure type has a public inline function call operator member template. 그리고 7.1.2/2: the use of inline keyword is to declare an inline function호출 시점에서 함수 본문을 인라인하는 것이 좋습니다. 따라서, 그것들이 동일하게 동작 할 수 있다고해도, 인라인 함수와 함수 템플릿은 여전히 ​​분리 될 수있는 직교적인 개념들 (즉, 인라인 함수 템플릿)입니다
paercebal

캡슐화가 깨졌습니까? 어떻게 요? 캡슐화는 메모리에있는 실제 객체가 아니라 guy (s) 프로그래밍을위한 것입니다. 그 시점에서 아무도 신경 쓰지 않습니다. 라이브러리를 배포하더라도 컴파일러는 자체적으로 인라인하거나하지 않도록 선택할 수 있습니다. 결국 새로운 lib를 얻으면 해당 라이브러리의 함수와 객체를 사용하는 모든 것을 다시 컴파일해야합니다.
FalcoGer

42

구식 C 및 C ++에서, 가능한 최적화에 대한 컴파일러에 대한 제안 (제안 이상의 것) inline은 다음과 register같습니다.

현대 C ++ inline에서 링커는 선언이 아닌 여러 정의가 다른 번역 단위에서 발견되면 모두 동일하며 링커는 자유롭게 하나를 유지하고 다른 하나는 모두 버릴 수 있습니다.

inline 헤더 파일에 함수 (복잡하거나 "선형")가 정의되어 있으면 링커에서 "다중 정의"오류를 발생시키지 않고 여러 소스에 해당 함수를 포함시킬 수 있어야합니다.

클래스 함수 내에 정의 된 멤버 함수는 기본적으로 템플릿 함수 (글로벌 함수와 달리) 인 "인라인"입니다.

//fileA.h
inline void afunc()
{ std::cout << "this is afunc" << std::endl; }

//file1.cpp
#include "fileA.h"
void acall()
{ afunc(); }

//main.cpp
#include "fileA.h"
void acall();

int main()
{ 
   afunc(); 
   acall();
}

//output
this is afunc
this is afunc

fileA.h를 두 개의 .cpp 파일에 포함 시키면 두 개의 인스턴스가 생성됩니다 afunc(). 링커는 그 중 하나를 버립니다. inline지정 하지 않으면 링커가 불평합니다.


16

인라이닝은 컴파일러에게 무시할 수있는 제안입니다. 작은 코드 비트에 이상적입니다.

함수가 인라인 된 경우 실제로 별도의 함수를 호출하지 않고 함수 호출이 수행되는 코드에 기본적으로 삽입됩니다. 실제 통화를하지 않아도 속도를 높일 수 있습니다.

또한 호출로 인해 새로운 명령으로 파이프 라인을 다시로드 할 필요가 없으므로 CPU가 파이프 라이닝을 지원합니다.

유일한 단점은 이진 크기를 늘릴 수 있다는 것입니다. 그러나 함수가 작 으면 아무리 중요하지 않습니다.

요즘에는 이런 종류의 결정을 컴파일러에 맡기는 경향이 있습니다 (물론 똑똑한 결정). 글을 쓴 사람들은 기본 아키텍처에 대해 훨씬 더 자세한 지식을 가지고 있습니다.


12

인라인 함수는 컴파일러에서 사용하는 최적화 기술입니다. 인라인 키워드를 함수 프로토 타입에 추가하여 함수를 인라인으로 만들 수 있습니다. 인라인 함수는 컴파일러가 해당 함수가 코드에서 사용 된 모든 함수를 삽입하도록 컴파일러에 지시합니다.

장점 :-

  1. 함수 호출 오버 헤드가 필요하지 않습니다.

  2. 또한 함수 호출 중에 스택에서 변수 push / pop의 오버 헤드를 저장합니다.

  3. 또한 함수에서 리턴 호출의 오버 헤드를 저장합니다.

  4. 명령 캐시를 활용하여 참조의 지역성을 높입니다.

  5. 인라인 컴파일러가 지정된 경우 절차 내 최적화도 적용 할 수 있습니다. 이것은 컴파일러가 죽은 코드 제거에 집중할 수 있고 분기 예측, 유도 변수 제거 등에 더 많은 스트레스를 줄 수있는 가장 중요한 방법입니다.

그것에 대한 자세한 내용을 보려면이 링크를 방문하십시오 http://tajendrasengar.blogspot.com/2010/03/what-is-inline-function-in-cc.html


4
1) 명령어가 아닌 제안입니다. 2) 일반적으로 사용되는 함수가 많이 인라인되면 코드 크기가 증가하여 더 많은 캐시 누락이 발생할 수 있습니다.
Flexo

3
링크가 개인 블로그 끝에 있습니까? 그렇다면이를 선언해야하며, 그렇지 않으면 스팸처럼 보입니다.
Flexo

6

공유 라이브러리를 구축 할 때 인라인 함수가 중요하다는 것을 추가하고 싶습니다. 함수를 인라인으로 표시하지 않으면 이진 형식으로 라이브러리로 내보내집니다. 내 보내면 기호 테이블에도 표시됩니다. 반면에 인라인 된 함수는 라이브러리 바이너리 나 기호 테이블로 내 보내지 않습니다.

라이브러리가 런타임에로드 될 때 중요 할 수 있습니다. 이진 호환 인식 라이브러리에 충돌 할 수도 있습니다. 이러한 경우 인라인을 사용하지 마십시오.


@ Johnsyweb : 내 대답을주의 깊게 읽으십시오. 당신이 말한 것은 실행 파일을 만들 때 사실입니다. 그러나 inline공유 라이브러리를 빌드 할 때 컴파일러는 단순히 무시할 수 없습니다 !
doc

4

최적화하는 동안 많은 컴파일러는 표시하지 않아도 함수를 인라인합니다. 일반적으로 올바른 결정을 내릴 수 있으므로 컴파일러가 모르는 것을 알고있는 경우 일반적으로 함수를 인라인으로 표시하면됩니다.


많은 컴파일러들도이 작업을 수행하지 않을 것입니다. 예를 들어 MSVC는 사용자가
지시

4

inline#include하나의 정의 규칙을 위반하지 않고 헤더 파일에 함수 정의를 배치하고 해당 헤더 파일을 여러 소스 파일에 배치 할 수 있습니다.


3

일반적으로 요즘 현대 컴파일러에서 인라인에 대해 걱정하는 것은 시간 낭비입니다. 컴파일러는 코드에 대한 자체 분석 및 컴파일러에 전달 된 최적화 플래그 지정을 통해 이러한 모든 고려 사항을 실제로 최적화해야합니다. 속도에 관심이 있다면 속도를 최적화하도록 컴파일러에 지시하십시오. 공간에 관심이 있다면 공간을 최적화하도록 컴파일러에 지시하십시오. 또 다른 대답에서 알 수 있듯이 괜찮은 컴파일러는 실제로 의미가 있다면 자동으로 인라인합니다.

또한 다른 사람들이 언급했듯이 인라인을 사용한다고해서 인라인이 보장되는 것은 아닙니다. 이를 보장하려면 인라인 함수 대신 매크로를 정의해야합니다.

포함을 강제하기 위해 매크로를 인라인 및 / 또는 정의 할 때? -애플리케이션의 전체 성능에 영향을 미치는 것으로 알려진 중요한 코드 섹션에 대해 입증되고 필요한 입증 된 속도 증가가있는 경우에만 해당됩니다.


… 공간에 관심이 있다면 컴파일러에게 공간 을 최적화하도록 지시하십시오. 컴파일러에 속도 를 최적화하도록 지시 하면 C ++ 및 C를 사용하는 바이너리가 더 작아 질 수 있습니다 . 마찬가지로 컴파일러에 공간을 최적화하도록 지시하면 실행 속도가 빨라질 수 있습니다. 이제 이러한 기능이 항상 광고 된대로 작동하지는 않습니다. 인간은 컴파일러의 일반화 된 해석 (사용 가능한 속도를 유지해야 함)보다 프로그램의 일부 측면을 더 잘 이해할 수 있습니다. 인간의 개입이 나쁜 것은 아닙니다.
저스틴

3

성능에만 관한 것은 아닙니다. C ++과 C는 모두 하드웨어 위에있는 임베디드 프로그래밍에 사용됩니다. 예를 들어, 인터럽트 핸들러를 작성하려면 추가 레지스터 및 / 또는 메모리 페이지를 바꾸지 않고 한 번에 코드를 실행할 수 있어야합니다. 인라인이 편리 할 때입니다. 좋은 컴파일러는 속도가 필요할 때 자체적으로 "인라인"을 수행하지만 "인라인"은이를 강제합니다.


1

라이브러리에 함수를 인라인하는 것과 같은 문제에 빠졌습니다. 인라인 함수는 라이브러리로 컴파일되지 않은 것 같습니다. 결과적으로 실행 파일이 라이브러리의 인라인 함수를 사용하려는 경우 링커에서 "정의되지 않은 참조"오류가 발생합니다. (gcc 4.5로 Qt 소스를 컴파일하는 일이 생겼습니다.


1

기본적으로 모든 기능을 인라인으로 설정하지 않는 이유는 무엇입니까? 엔지니어링 트레이드 오프이기 때문입니다. "최적화"에는 최소한 두 가지 유형이 있습니다. 프로그램 속도를 높이고 프로그램의 크기 (메모리 공간)를 줄입니다. 인라인은 일반적으로 속도를 높입니다. 스택에서 매개 변수를 밀고 당기는 것을 피하면서 함수 호출 오버 헤드를 제거합니다. 그러나 모든 함수 호출은 이제 함수의 전체 코드로 대체되어야하기 때문에 프로그램의 메모리 풋 프린트가 더 커집니다. 보다 복잡한 작업을 수행하기 위해 CPU는 자주 사용되는 메모리 청크를 CPU의 캐시에 저장하여 매우 빠른 액세스를 수행합니다. 프로그램의 메모리 이미지를 충분히 크게 만들면 프로그램에서 캐시를 효율적으로 사용할 수 없으며 최악의 경우 인라인으로 인해 실제로 프로그램 속도가 느려질 수 있습니다.


1

우리의 컴퓨터 과학 교수는 C ++ 프로그램에서 인라인을 사용하지 말라고 촉구했습니다. 이유를 물었을 때, 그는 현대 컴파일러가 인라인을 언제 자동으로 사용해야하는지 감지해야한다고 친절하게 설명했습니다.

따라서 인라인은 가능한 곳에서 사용되는 최적화 기술이 될 수 있지만 분명히 함수를 인라인 할 수있을 때마다 이미 수행 된 것입니다.


5
교수님은 불행히도 완전히 잘못되었습니다. inlineC ++의 두 가지 의미는 매우 명확합니다. 그중 하나만 최적화와 관련이 있으며 교수는 이에 대해 정확합니다. 그러나 두 번째 의미 inline는 종종 하나의 정의 규칙 을 충족시키기 위해 필요합니다 .
Konrad Rudolph

-1

다른 토론 에서 결론 :

인라인 함수의 단점이 있습니까?

인라인 함수를 사용하는 데 아무런 문제가 없습니다.

그러나 다음 사항에 주목할 가치가 있습니다!

  • 인라인을 과도하게 사용하면 실제로 프로그램 속도가 느려질 수 있습니다. 함수의 크기에 따라 인라인하면 코드 크기가 증가하거나 감소 할 수 있습니다. 매우 작은 접근 자 함수를 인라인하면 일반적으로 코드 크기가 줄어들고 매우 큰 함수를 인라인하면 코드 크기가 크게 증가 할 수 있습니다. 최신 프로세서에서는 명령 캐시를 더 잘 사용하기 때문에 일반적으로 작은 코드가 더 빠르게 실행됩니다. -Google 가이드 라인

  • 인라인 함수의 속도 이점은 함수의 크기가 커짐에 따라 감소하는 경향이 있습니다. 어떤 시점에서 함수 호출의 오버 헤드가 함수 본문의 실행에 비해 작아지고 이점이 사라집니다 .-소스

  • 인라인 함수가 작동하지 않는 상황은 거의 없습니다.

    • 값을 반환하는 함수의 경우; 리턴 문이 존재하는 경우
    • 값을 반환하지 않는 함수 루프, 스위치 또는 goto 문이 존재하는 경우
    • 함수가 재귀적인 경우 -출처
  • __inline키워드는 최적화 옵션을 지정하는 경우 함수는 인라인됩니다. optimize가 지정되면 __inline인라인 최적화 프로그램 옵션의 설정에 따라 달라집니다. 기본적으로 인라인 옵션은 옵티마이 저가 실행될 때마다 유효합니다. optimize를 지정하면 __inline키워드를 무시 하려면 noinline 옵션도 지정해야합니다 . -출처


3
인라인이 명령이고 컴파일러에 대한 힌트가 아닌 경우에 해당됩니다. 컴파일러는 실제로 무엇을 인라인할지 결정합니다.
Martin York

1
@LokiAstari 필자는 인라인이 컴파일러 요청이라는 것을 알고 있습니다. 내 주장은 컴파일러에 대한 힌트라면 컴파일러에게 맡겨야 무엇이 최선인지 결정해야한다. 인라인을 사용하더라도 인라인을 사용하는 이유는 여전히 최종 결정을 내리는 컴파일러입니다. Microsoft가 _forceinline을 도입했는지 궁금합니다.
크리슈나 오자

@ krish_oza : 여기 내 의견. 이 답변에 관한 것입니다. 여기에 대한 대답은 완전히 잘못되었습니다. 컴파일러는 인라인 코드를 작성 할지 여부를 결정 하는 inline키워드 무시하기 때문에 위에서 언급 한 모든 사항이 잘못되었습니다. 컴파일러가 인라인에 키워드를 사용한 경우에 해당됩니다 (링크 목적으로 여러 정의를 표시하는 데만 사용됨).
Martin York
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.