본문 바로가기

프로그래밍/Modern C++

[C++] PIMPL을 사용하지 말자

개요

PIMPL(Pointer to Implementation)은 컴파일 방화벽으로 사용하는 코딩 관용구로 헤더 파일 하나를 수정했을 때 많은 소스 파일이 재 컴파일하지 않게 해주는 메커니즘이다. 1990년대 C++ 이 사춘기를 보내던 시절에는 PIMPL 관용구의 사용이 정당화되었는데 현재는 PIMPL을 사용할 필요가 거의 없다. 현재 컴파일하는 데 걸리는 시간은 1990년대에 걸렸던 시간의 1%에 불과하기 때문이며 BigClass를 깨서 조금 더 초점을 맞춘 인터페이스를 제공하는 방법이 PIMPL을 구현하는 방법만큼 효율적일 수 있다. [1]

 

 

PIMPL 소스코드

PIMPL을 사용하지 않는 코드는 다음과 같다.

 

1
2
3
4
5
6
7
8
9
10
11
12
#pragma once
 
#include<vector>
#include<string>
 
class Test {
public:
    std::vector<std::string> s;
};
 
 
 

이 코드의 문제점은 Vector와 String 헤더 파일에 의존성이 생겨서 헤더파일에 변경이 생기면 재컴파일 해야하는 문제가 있다. 이 코드를 PIMPL 패턴을 사용해서 바꾸면 다음과 같다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
 
#pragma once
 
#include<memory> //스마트 포인터
 
class Pimpl; //전방선언
 
class Test {
public:
    std::shared_ptr<Pimpl> pimpl_;
    Test();
    void PrintString();
};

 

먼저 헤더파일에 Vector와 String 헤더 파일을 지우고 Pimpl이라는 클래스를 전방 선언 후 C++11 표준에 있는 스마트 포인터인 Shared_ptr을 사용한다 Unique_ptr은 다른 조치를 좀 해줘야 작동한다. 자세한 내용은(  Effective Modern C++(인사이트) 책에 소개가 나와있다.)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<vector>
#include<string>
#include<iostream>
#include"Pimpl.h" //Test Class 헤더파일
 
//Pimpl Class 정의
class Pimpl {
public:
    std::vector<std::string>s;
};
 
Test::Test():pimpl_(std::make_shared<Pimpl>()) {
    std::string temp = "HELLO WORLD!\n";
    pimpl_->s.emplace_back(temp);
    pimpl_->s.emplace_back(temp);
    pimpl_->s.emplace_back(temp);
}
 
void Test::PrintString() {
 
    for (const auto& i : pimpl_->s) {
        std::cout << i;
    }
}
 
 
int main() {
    Test t;
 
    t.PrintString();
 
}
 

 

 

그 후에 Pimpl 클래스를 구현부(CPP)에서 작성 후 다음과 같이 사용하면 컴파일 의존성을 줄일 수 있다. 이 외에도 구현부와 선언부가 나뉜다는 장점도 존재한다.

 

후기

현재 A* 알고리즘을 이용한 프로젝트에 PIMPL 패턴을 사용해서 작성을 하고 있는데 C++최적화 책에서 사용해봐야 별 의미가 없다는 말을 듣고 글을 간단하게 작성하였다. 사용이 어려운 패턴도 아니고 이 정도 예시만 봐도 충분히 구현이 가능하기 때문에 짧게 작성했다 

내가 생각하는 이 패턴의 단점은 구현부가 좀 더러워지는 단점이 있고 책에서 말하기에는 인라인 될 수 있는 class의 멤버 함수는 호출하는 코드가 필요합니다?(번역이 좀 이상한 거 같은데) 이러한 단점이 있다고 한다.

지금 작성하는 프로젝트에 PIMPL을 빼야할지 고민이며 이러한 패턴이 있다는 정도만 알면 도움이 될 거 같다.

 

출처

[1] [커트 컨서로스] [C++최적화]: 한빛미디어