[C++] 항목 30: 인라인 함수는 미주알고주알 따져서 이해해 두자

업데이트:     Updated:

카테고리:

태그:

이 글은 아래의 책을 자세히 정리한 후, 정리한 글을 GPT에게 요약을 요청하여 작성되었습니다.
이펙티브 C++ 제3판, 스콧 마이어스 저자, 곽용재 번역

📦 5. 구현

👉🏻 항목 30: 인라인 함수는 미주알고주알 따져서 이해해 두자

🪄 인라인 함수란?

inline 키워드를 사용하여 컴파일러에게 함수의 코드를 호출 지점에 직접 삽입하는 기능

인라인 함수는 함수 호출의 오버헤드를 줄이기 위한 최적화 기법이지만, 신중하게 사용해야 한다.

장점:

  • 본문의 길이가 짧은 인라인 함수를 사용하면 → 함수 호출의 오버헤드를 줄이고, 성능을 향상시킬 수 있다

단점:

  • 남발하면 코드의 크기가 커진다 → 페이징 횟수가 늘어나고 명령어 캐시 적중률이 떨어질 수 있다
  • 라이브러리 차원에서 바이너리 업그레이드를 제공할 수 없다 (이후 설명)
  • 디버그하기 힘들다 (이후 설명)

특징:

  • 대체적으로 헤더 파일에 들어가 있어야 한다
  • 함수 인라인은 컴파일 타임에 진행된다
  • 인라인은 컴파일러 선에서 무시될 수 있다 (이후 설명)

✅ inline 기능을 사용하는 방법

1. 암시적 방법

class Person {
public:
	...
	// 클래스 정의 내부에서 정의
	int age() const { return theAge; }
	...

private:
	int theAge;
};

클래스 정의 내부에서 함수를 정의하면 자동으로 인라인 함수가 된다.

2. 명시적 방법

template <typename T>
// inline 키워드를 통한, 명시적 인라인 요청
inline const T& max(const T& a, const T& b) {
	return a<b ? b:a;
}

inline 키워드를 명시적으로 사용하여 인라인 함수임을 표시한다.

주의점:

  • 함수 템플릿은 반드시 인라인 함수일 필요는 없다

✅ 인라인이 무시되는 경우들

인라인은 컴파일러에 대한 요청일 뿐이며, 다음과 같은 경우 컴파일러가 인라인을 무시할 수 있다:

인라인이 무시되는 상황:

  • 가상함수 호출
  • 함수 포인터 호출
  • 어떤 배열의 원소가 객체일 경우
    → 객체의 생성자/소멸자의 함수 포인터를 필요
    → 함수 본문이 필요해짐

💀 생성자와 소멸자의 함정

class Base {
public:
	...

private:
	string bm1, bm2;
};

class Derived : public Base {
public:
	Derived() {}  // 비어보이지만 실제로는 복잡함
	...

private:
	string dm1, dm2, dm3;
};

문제:

  • 생성자와 소멸자는 인라인하기에 좋지 않음
  • 비어보이지만, 기본 생성자가 숨어있음
  • 실제로는 기본 클래스 생성자 호출, 멤버 초기화 등의 복잡한 코드가 생성됨

❎ 인라인 함수의 단점들

1. 라이브러리 바이너리 업그레이드 문제

문제 상황:

  • 라이브러리에 f라는 인라인 함수가 있고, 이 라이브러리를 쓰는 사용자가 f의 본문을 컴파일해서 응용 프로그램을 만듬
  • 라이브러리 개발자가 f의 내부를 변경하면, f를 사용한 사용자들은 모두 다시 컴파일 해주어야 함

비교:

  • f가 인라인 함수가 아닌, 일반 함수였다면 링크만 다시 해주면 된다

2. 디버깅의 어려움

문제:

  • 존재하지 않는 함수에 중단점을 걸 수 없음
  • 인라인 함수의 디버깅을 지원해주기도 하지만, 디버그 빌드에 대해 인라인을 비활성화해주기도 함

📌 인라인 함수 사용 지침

언제 사용해야 하는가?

  1. 아무것도 인라인하지 않아도 상관없다
    • 성능상 문제가 없다면 굳이 사용할 필요 없음
  2. 꼭 인라인해야 하는 함수
    • 호출 빈도가 매우 높고 성능이 중요한 함수
  3. 정말 단순한 함수
    • 함수 본문이 매우 짧고 간단한 경우에만

권장사항

인라인 함수는 성능 측정 결과를 바탕으로 신중하게 선택하자. 단순히 성능이 좋아질 것이라는 추측만으로는 사용하지 말자.


🧐 정리

  • 인라인 함수는 함수 호출 오버헤드를 줄일 수 있지만, 코드 크기 증가캐시 효율성 저하를 가져올 수 있다.
  • 클래스 정의 내부에서 정의된 함수는 암시적으로 인라인이 되며, inline 키워드를 통해 명시적으로 요청할 수도 있다.
  • 인라인은 컴파일러에 대한 요청일 뿐이며, 가상함수나 함수 포인터 등의 경우 무시될 수 있다.
  • 생성자와 소멸자는 비어보여도 실제로는 복잡한 코드가 생성되므로 인라인하기에 적합하지 않다.
  • 인라인 함수는 라이브러리 업그레이드와 디버깅을 어렵게 만들 수 있으므로 신중하게 사용하자.
  • 함수 인라인은 작고, 자주 호출되는 함수에 대해서만 하는 것으로 묶자.
    • 디버깅 및 라이브러리의 바이너리 업그레이드가 용이해짐.
    • 코드 부풀림 현상 최소화
    • 프로그램 속력 더 빨라질 여지
  • 함수 템플릿이 대개 헤더 파일에 들어간다는 생각으로, inline으로 선언하면 안된다.

Cpp 카테고리 내 다른 글 보러가기

댓글남기기