class Person
{
public:
...
int age() const { return theAge;} // 암시적 인라인 요청
...
private:
int theAge;
};
template<typename T>
inline const T& max(const T& a, const T& b) { return a < b ? b : a; } // 명시적 인라인 요청
그러나 대부분의 컴파일러는 인라인 함수로 선언되어있어도 복잡한 함수(ex. 재귀, 루프, ...)와 가상 함수는 인라인하지 않는다.
즉, 실제로 인라인이 되는지는 컴파일러가 결정한다.
inline void f() { ... } // 인라인 함수
void (*pf) () = f; // f를 가리키는 함수 포인터
...
f(); // 인라인
pf(); // 아웃라인
인라인 함수의 주소를 취하는 코드가 있으면, 컴파일러는 이 코드를 위해 아웃라인 함수 본문을 만들어야만 한다.
따라서 확실한 인라인 함수도 어떻게 호출하느냐에 따라 인라인되기도, 안되기도 한다.
생성자, 소멸자는 런타임에 아웃라인 본문을 만들어버릴 수 있다.
이렇게 런타임에 본문이 바뀔 수 있으므로 인라인하기 적합하지 않다.
class Base
{
public:
...
private:
std::string bm1, bm2;
};
class Derived: public Base
{
public:
Derived() {}
private:
std::string dm1, dm2, dm3;
};
여기서 Derived
의 생성자는 인라인하기 좋아 보이지만 실상은 그렇지 않다.
C++은 객체가 생성될 때 객체의 데이터 멤버들도 생성하고, 객체가 소멸될 때 객체의 데이터 멤버들을 소멸한다.
따라서 함수 본문이 비어있어보여도, 실제로는 데이터 멤버를 생성/삭제하는 코드들이 포함될 수 있다.
결론
- 작고, 자주 호출되는 함수만 인라인하자.