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

Minsu._.Lighting·2023년 12월 6일
0

[ Effective C++ ] 정리 모음집
" C++ 프로그래머의 필독서, 스콧 마이어스의 Effective C++ 를 읽고 내용 요약 / 정리 "

[핵심]

" 인라인 함수는 아무리 생각해도 훌륭한 아이디어! 그렇기에 더 제대로 알아두자! "

  • 함수 인라인은 작고, 자주 호출되는 함수에 대해서만 하는 것으로 묶어두자!
  • 함수 템플릿이 대개 헤더 파일에 들어간다는 일반적인 부분만 생각해서 이들을 inline으로 선언하면 안된다!

💡 인라인 함수

  • 함수처럼 보이고 함수처럼 동작

  • 매크로 보다 훨씬 안전하고 쓰기 좋다
    - [ 항목 2 : #define을 쓰려거든 const, enum, inline을 떠올리자 ] 참조

  • 함수 호출 시 발생하는 오버헤드도 걱정할 필요 없다

  • 사용 시 컴파일러가 함수 본문에 대해 문맥별 최적화를 걸기가 용이해진다
    - 대체적으로 컴파일러 최적화는 함수 호출이 없는 코드가 연속적으로 이어지는 구간에 적용되도록 설계되었기 때문

📌 인라인 함수 사용시 주의할 점

  • 목적 코드의 크기가 커질 수 있다
    - 메모리가 제한된 컴퓨터에서 인라인 함수를 남발했다간 프로그램 크기가 정해진 공간의 크기를 넘어버릴 수 있다
    - 가상 메모리를 쓰는 환경일지라도 성능의 걸림돌이 될 수 있다.

  • 페이징 횟수가 늘어나고, 명령어 캐시 적중률이 떨어질 가능성도 높아진다

  • 반대의 경우(본문 길이가 굉장히 짧은 경우) 상황이 바뀐다는 것도 기억하자

💡 인라인 함수 사용 방법

  • inline은 컴파일러에게 '명령'을 하는 것이 아닌 '요청'을 하는 것!

  • 암시적, 명시적 방법이 있다

📌 암시적

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; }
  • 함수 정의 앞에 inline 키워드를 붙이는 것

📌 인라인 함수는 대체적으로 헤더 파일에 있어야 한다!

  • 대부분의 빌드 환경에서 인라인을 컴파일 도중에 수행하기 떄문
    - 인라인 함수 호출을 본문과 바꿔치기 하려면 컴파일러는 그 함수가 어떤 형태인지 알고 있어야 한다

📌 인라인 함수로 선언이 되어 있어도 복잡한 함수는 컴파일러가 인라인화 해주지 않는다!

  • 루프가 들어있거나 재귀 함수인 경우

  • 가상 함수를 호출한 경우
    - virtual과 inline 둘의 의미만 보아도 말이 안된다.
    - virtual의 의미 : 어떤 함수를 호출 할지 결정하는 작업을 실행 중에 한다
    - inline의 의미 : 함수 호출 위치에 호출된 함수를 끼워 넣는 작업을 프로그램 실행 전에 한다



💡 인라인의 조건을 갖추어도 인라인 화 될 수 없는 경우

📌 함수 포인터의 경우

inline void f() { ... }				// 인라인 함수
void (*pf) () = f;					// f를 가리키는 함수 포인터
...
f();								// 인라인 성공
pf();								// 함수 포인터를 통한 호출 이므로 인라인 실패

📢 함수 포인터를 사용하지 않아도 생기는 문제

  • 어떤 배열의 원소가 객체일 경우
    - 배열을 구성하는 객체들을 생성 · 소멸 시킬 떄 생성자 · 소멸자의 함수 포인터를 얻어내려면 함수 본문이 반드시 필요 하기 때문

📌 생성자 · 소멸자의 경우

[ 예시 코드 ]

class Base
{
private:
  std::string bm1, bm2;
};

class Derived: public Base
{
public:
  Derived() {}
private:
  std::string dm1, dm2, dm3;
};
  • Derived의 생성자가 비어있는 것 처럼 보이지만 정말 비어있을까??

[ 동작 방식 유추 ]

class Derived: public Base
{
public:
  Derived() 
  {
    Base::Base();

    try { dm1.std::string::string(); }			// dm1 생성 도중 예외를 던지면?
    catch (...)									// 기본 클래스 부분 소멸 후 예외 전파
    {
      Base::~Base();
      throw;
    }
    // dm2, dm3 에 대해서도 위와 동일
  }
private:
  std::string dm1, dm2, dm3;
};
profile
오코완~😤😤

0개의 댓글

관련 채용 정보