헤더에 C ++ 인라인 함수가있는 이유는 무엇입니까?


120

NB 이것은 인라인 함수를 사용하는 방법이나 작동 방식에 대한 질문이 아닙니다.

클래스 멤버 함수의 선언은 함수를로 정의 할 필요가 없으며 함수 inline의 실제 구현 일뿐입니다. 예를 들어, 헤더 파일에서 :

struct foo{
    void bar(); // no need to define this as inline
}

그렇다면 클래스 함수의 인라인 구현이 헤더 파일에 있어야 하는 이유는 무엇입니까? 인라인 기능을 .cpp파일에 넣을 수없는 이유는 무엇 입니까? 인라인 정의를 .cpp파일 에 넣으려고하면 다음 과 같은 오류가 발생합니다.

error LNK2019: unresolved external symbol 
"public: void __thiscall foo::bar(void)"
(?bar@foo@@QAEXXZ) referenced in function _main 
1>C:\Users\Me\Documents\Visual Studio 2012\Projects\inline\Debug\inline.exe 
: fatal error LNK1120: 1 unresolved externals



@Charles 두 번째 링크가 비슷하다고 말하고 싶지만 인라인이 작동하는 방식의 논리에 대해 더 많이 묻습니다.
thecoshman

2
이 경우 "인라인"또는 "헤더 파일"을 오해했을 수도 있습니다. 당신의 주장 중 어느 것도 사실이 아닙니다. 멤버 함수의 인라인 구현을 가질 수 있고 헤더 파일에 인라인 함수 정의를 넣을 수 있습니다. 단지 좋은 생각이 아닐 수도 있습니다. 질문을 명확히 할 수 있습니까?
CB Bailey

편집 후, inline정의에 나타날 때 상황에 대해 질문 할 수 있지만 이전 선언은 아니지만 그 반대의 경우도 마찬가지 입니다. 그렇다면 도움이 될 수 있습니다. stackoverflow.com/questions/4924912/…
CB Bailey

답변:


122

inline함수 의 정의는 헤더 파일에있을 필요는 없지만 인라인 함수에 대한 하나의 정의 규칙 ( ODR )으로 인해 함수에 대한 동일한 정의가이를 사용하는 모든 번역 단위에 존재해야합니다.

이를 달성하는 가장 쉬운 방법은 헤더 파일에 정의를 넣는 것입니다.

단일 소스 파일에 함수 정의를 넣으려면 선언하지 않아야합니다 inline. 선언 inline되지 않은 함수 는 컴파일러가 함수를 인라인 할 수 없음을 의미하지 않습니다.

함수를 선언해야하는지 여부 inline는 일반적으로 하나의 정의 규칙 중 어떤 버전을 따라야 하는지를 기준으로 선택해야합니다 . 추가 inline하고 후속 제약에 의해 제한되는 것은 거의 의미가 없습니다.


그러나 컴파일러는 .h 파일을 포함하는 .cpp 파일을 컴파일하지 않습니다. 따라서 .cpp 파일을 컴파일 할 때 소스 파일과 함께 감속도를 모두 갖습니다. 끌어온 다른 헤더 파일은 컴파일러가 해당 함수가 존재하고 다른 소스 파일에서 구현 될 것이라는 것을 '신뢰'할 수 있도록하기위한 것입니다
thecoshman

1
이것은 실제로 +1저 보다 훨씬 더 나은 대답입니다 .
sbi

2
@thecoshman : 두 가지 차이점이 있습니다. 소스 파일과 헤더 파일. 관례 상 헤더 파일은 일반적으로 번역 단위의 기초가 아니지만 다른 소스 파일에서 #include 된 소스 파일을 참조합니다. 그런 다음 선언 대 정의가 있습니다. 헤더 파일 또는 '일반'소스 파일에서 함수의 선언 또는 정의를 가질 수 있습니다. 귀하의 의견에서 무엇을 요구하고 있는지 잘 모르겠습니다.
CB Bailey

걱정하지 마세요, 왜 지금인지 알 수 있습니다 ... 누가이 질문에 정말로 대답했는지는 모르겠습니다. 당신과 @Xanatos의 대답의 조합이 나를 위해 설명했습니다.
thecoshman

113

두 가지 방법으로 볼 수 있습니다.

  1. 함수 호출을 인라인하려면 컴파일러가 함수 본문을 볼 수 있어야하므로 인라인 함수는 헤더에 정의됩니다. 순진한 컴파일러가이를 수행하려면 함수 본문이 호출과 동일한 번역 단위에 있어야합니다. (최신 컴파일러는 번역 단위 전체에서 최적화 할 수 있으므로 함수 정의가 별도의 번역 단위에 있더라도 함수 호출이 인라인 될 수 있지만 이러한 최적화는 비용이 많이 들고 항상 활성화되지 않으며 항상 지원되지는 않았습니다. 컴파일러)

  2. 헤더에 정의 된 함수는 표시되어야합니다. inline그렇지 않으면 헤더를 포함하는 모든 번역 단위에 함수의 정의가 포함되고 링커는 여러 정의에 대해 불평 할 것입니다 (단일 정의 규칙 위반). inline키워드는 여러 번역 단위 (동일) 정의를 포함 할 수 있도록이를 억제한다.

두 가지 설명은 inline키워드가 예상 한대로 정확하게 작동하지 않는다는 사실로 귀결됩니다 .

C ++ 컴파일러는 프로그램의 관찰 가능한 동작을 변경하지 않는 한 언제든지 인라인 최적화 (함수 호출을 호출 된 함수의 본문으로 대체하여 호출 오버 헤드 절약 )를 자유롭게 적용 할 수 있습니다.

inline키워드를 만들어 쉽게 함수 정의가 여러 번역 단위로 볼 수 있도록 허용하지만, 컴파일러를 의미하지 않는다 키워드를 사용하여,이 최적화를 적용 할 컴파일러 했다 함수를 인라인하고, 하지 않는 키워드를 사용하여 컴파일러가 함수를 인라인하는 것을 금지합니다.


23

이것은 C ++ 컴파일러의 한계입니다. 함수를 헤더에 넣으면 인라인 될 수있는 모든 cpp 파일이 함수의 "소스"를 볼 수 있으며 컴파일러에서 인라인을 수행 할 수 있습니다. 링커가 인라인을 수행해야하는 경우도 있습니다 (각 cpp 파일은 obj 파일에서 개별적으로 컴파일됩니다). 문제는 링커에서 수행하는 것이 훨씬 더 어려울 것이라는 것입니다. "템플릿"클래스 / 함수에도 유사한 문제가 있습니다. 링커가 인스턴스화 (특수 버전 생성)하는 데 문제가 있기 때문에 컴파일러에 의해 인스턴스화되어야합니다. 일부 최신 컴파일러 / 링커는 컴파일러가 첫 번째 단계를 수행하는 "2 단계"컴파일 / 링크를 수행 한 다음 링커가 작업을 수행하고 컴파일러를 호출하여 해결되지 않은 사항 (인라인 / 템플릿 ...)을 해결할 수 있습니다.


아 그렇군요! 예, 클래스 자체가 아닌 인라인 함수를 사용하는 다른 코드 인라인 함수를 사용합니다. 인라인되는 클래스의 헤더 파일 만 볼 수 있습니다!
thecoshman

11
이 답변에 동의하지 않습니다. C ++ 컴파일러 제한이 아닙니다. 순전히 언어 규칙이 지정되는 방식입니다. 언어 규칙은 간단한 컴파일 모델을 허용하지만 대체 구현을 금지하지는 않습니다.
CB Bailey

3
@Charles에 동의합니다. 실제로 번역 단위에 함수를 인라인하는 컴파일러가 있으므로 이는 컴파일러 제한 때문이 아닙니다.
sbi

5
이 답변에는 기술적 오류가있는 것 같지만 컴파일러가 헤더 파일 등에서 작동하는 방식을 보는 데 도움이되었습니다.
thecoshman

10

그 이유는 컴파일러가 호출 대신 정의 를 드롭 할 수 있도록 실제로 정의 를 확인해야하기 때문입니다.

C와 C ++는 컴파일러가 항상 한 번에 하나의 번역 단위 만 보는 매우 단순한 컴파일 모델을 사용합니다. (이는 수출에 실패하며 이는 단 하나의 공급 업체에서만 실제로 구현 한 주된 이유입니다.)


9

C ++ inline키워드는 오해의 소지가 있으며 "이 함수를 인라인"한다는 의미는 아닙니다. 함수가 인라인으로 정의되면 모든 정의가 동일하면 여러 번 정의 할 수 있다는 의미입니다. inline호출 된 지점에서 코드를 인라인하는 대신 호출되는 실제 함수로 표시된 함수는 완벽하게 합법적입니다 .

헤더 파일에 함수를 정의하는 것은 템플릿에 필요합니다. 예를 들어 템플릿 클래스는 실제로 클래스가 아니기 때문에 여러 변형을 만들 수있는 클래스 의 템플릿 입니다. 컴파일러가 예를 들어 Foo 템플릿을 사용하여 Foo 클래스를 만들 때Foo<int>::bar() 함수를 만들 수 있으 려면 의 실제 정의 Foo<T>::bar()가 표시되어야합니다.


그것 때문에 그리고 클래스에 대한 템플릿 , 그것은 호출되지 않습니다 템플릿 클래스 ,하지만 클래스 템플릿 .
sbi

4
첫 번째 단락은 완전히 옳지 만 ( "오해의 소지가 있음"을 강조 할 수 있기를 바랍니다), 템플릿에 비평 등 화가 필요하다고 생각하지 않습니다.
Thomas Edleson

어떤 컴파일러는 함수가 할 수있는 힌트로 사용합니다 아마 인라인 될 수 있지만, 실제로, 당신이 그것을 선언해서 인라인 보장 할 수 없습니다 inline(도 아니다-선언하지 않는 inline것이 인라인되지 않는다는 것을 보장).
Keith M

4

나는 이것이 오래된 스레드라는 것을 알고 있지만 extern키워드를 언급해야한다고 생각했습니다 . 나는 최근 에이 문제를 만났고 다음과 같이 해결했습니다.

Helper.h

namespace DX
{
    extern inline void ThrowIfFailed(HRESULT hr);
}

Helper.cpp

namespace DX
{
    inline void ThrowIfFailed(HRESULT hr)
    {
        if (FAILED(hr))
        {
            std::stringstream ss;
            ss << "#" << hr;
            throw std::exception(ss.str().c_str());
        }
    }
}

6
일반적으로 WPO (전체 프로그램 최적화)를 사용하지 않는 한 함수가 실제로 인라인되지는 않습니다.
Chuck Walbourn 2014 년

3

컴파일러는 그들을 인라인 하기 위해 그들을 볼 필요가 있기 때문 입니다. 헤더 파일은 일반적으로 다른 번역 단위에 포함되는 "구성 요소"입니다.

#include "file.h"
// Ok, now me (the compiler) can see the definition of that inline function. 
// So I'm able to replace calls for the actual implementation.

1

인라인 함수

C ++에서 매크로는 인라인 함수일뿐입니다. 이제 매크로는 컴파일러의 제어를받습니다.

  • 중요 : 클래스 내부에 함수를 정의하면 자동으로 인라인이 됩니다.

Inline 함수의 코드는 호출 된 위치에서 대체되므로 함수 호출의 오버 헤드를 줄일 수 있습니다.

어떤 경우에는 기능의 인라인이 작동하지 않을 수 있습니다.

  • 인라인 함수 내에서 정적 변수를 사용하는 경우.

  • 기능이 복잡하다면.

  • 함수의 재귀 호출

  • 함수의 주소가 암시 적으로 또는 명시 적으로 취해진 경우

아래와 같이 클래스 외부에 정의 된 함수는 인라인이 될 수 있습니다.

inline int AddTwoVar(int x,int y); //This may not become inline 

inline int AddTwoVar(int x,int y) { return x + y; } // This becomes inline

클래스 내부에 정의 된 함수도 인라인이됩니다.

// Inline SpeedMeter functions
class SpeedMeter
{
    int speed;
    public:
    int getSpeed() const { return speed; }
    void setSpeed(int varSpeed) { speed = varSpeed; }
};
int main()
{
    SpeedMeter objSM;
    objSM.setSpeed(80);
    int speedValue = A.getSpeed();
} 

여기서 getSpeed ​​및 setSpeed ​​함수는 모두 인라인이됩니다.


어, 아마도 좋은 정보가 있지만, 그 이유 를 실제로 설명하려고 시도하지는 않습니다 . 당신은 할 수 있지만 그것을 명확하게하지 않고 있습니다.
thecoshman

2
다음 문장은 사실이 아닙니다. "중요 : 클래스 내부에 함수를 정의하면 자동으로 인라인이됩니다."선언 / 정의에 "인라인"이라고 써도 실제로 인라인되고 있는지 확인할 수 없습니다. 템플릿도 아닙니다. 컴파일러가 자동으로 "inline"키워드를 가정하지만 따를 필요가 없다는 것을 의미했을 수도 있습니다. 그리고 제가 알아 차린 것은 대부분의 경우 간단한 constexpr 함수에 대해서도 인라인하지 않는다는 것입니다. 기본 산술.
Pablo Ariel

의견을 보내 주셔서 감사합니다 ... 아래는 Thinking in C ++ micc.unifi.it/bertini/download/programmazione/… 페이지 400 .. 확인 해주세요 .. 동의하면 찬성 해주세요. 감사합니다 ..... 클래스 내부 인라인 인라인 함수를 정의하려면 일반적으로 함수 정의 앞에 인라인 키워드를 붙여야합니다. 그러나 이것은 클래스 정의 내에서 필요하지 않습니다. 클래스 정의 내에서 정의하는 모든 함수는 자동으로 인라인입니다.
Saurabh Raoot

이 책의 저자는 코드가 아닌 책을 작성하기 때문에 원하는 것을 주장 할 수 있습니다. 이것은 인라인 코드를 최대한 피함으로써 휴대용 3D 데모를 64kb 미만으로 만들기 위해 깊이 분석해야하는 부분입니다. 프로그래밍은 종교가 아니라 사실에 관한 것입니다. 따라서 일부 "신 프로그래머"가 실제로 일어나는 일을 나타내지 않는 경우 책에서 언급해도 문제가되지 않습니다. 그리고 대부분의 C ++ 서적에는 나쁜 조언 모음이 있습니다. 때때로 레퍼토리에 추가 할 멋진 트릭을 찾을 수 있습니다.
Pablo Ariel

이봐 @PabloAriel 덕분에 ... 내가 분석에 따라이 대답을 업데이트 확인입니다 .. 분석하고 알려 주시기 바랍니다
Saurabh Raoot
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.