[C++] 항목 30: 인라인 함수는 미주알고주알 따져서 이해해 두자
카테고리: Cpp
태그: Cpp
이 글은 아래의 책을 자세히 정리한 후, 정리한 글을 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. 디버깅의 어려움
문제:
- 존재하지 않는 함수에 중단점을 걸 수 없음
- 인라인 함수의 디버깅을 지원해주기도 하지만, 디버그 빌드에 대해 인라인을 비활성화해주기도 함
📌 인라인 함수 사용 지침
언제 사용해야 하는가?
- 아무것도 인라인하지 않아도 상관없다
- 성능상 문제가 없다면 굳이 사용할 필요 없음
- 꼭 인라인해야 하는 함수
- 호출 빈도가 매우 높고 성능이 중요한 함수
- 정말 단순한 함수
- 함수 본문이 매우 짧고 간단한 경우에만
권장사항
인라인 함수는 성능 측정 결과를 바탕으로 신중하게 선택하자. 단순히 성능이 좋아질 것이라는 추측만으로는 사용하지 말자.
🧐 정리
- 인라인 함수는 함수 호출 오버헤드를 줄일 수 있지만, 코드 크기 증가와 캐시 효율성 저하를 가져올 수 있다.
- 클래스 정의 내부에서 정의된 함수는 암시적으로 인라인이 되며, inline 키워드를 통해 명시적으로 요청할 수도 있다.
- 인라인은 컴파일러에 대한 요청일 뿐이며, 가상함수나 함수 포인터 등의 경우 무시될 수 있다.
- 생성자와 소멸자는 비어보여도 실제로는 복잡한 코드가 생성되므로 인라인하기에 적합하지 않다.
- 인라인 함수는 라이브러리 업그레이드와 디버깅을 어렵게 만들 수 있으므로 신중하게 사용하자.
- 함수 인라인은 작고, 자주 호출되는 함수에 대해서만 하는 것으로 묶자.
- 디버깅 및 라이브러리의 바이너리 업그레이드가 용이해짐.
- 코드 부풀림 현상 최소화
- 프로그램 속력 더 빨라질 여지
- 함수 템플릿이 대개 헤더 파일에 들어간다는 생각으로, inline으로 선언하면 안된다.
댓글남기기