일상 코딩
[C++ 스마트포인터 시리즈 6] 가독성 향상과 인터페이스 설계 (Clean C++) 본문
Step 1부터 4까지 우리는 C++ 스마트 포인터의 '암호'와 '작동 원리'를 파헤쳤습니다. 하지만 실제 프로젝트(Drogon이나 ROS 걷어내기 프레임워크)를 보면, 정작 코드가 너무 길고 템플릿(<>)이 복잡해서 로직이 한눈에 들어오지 않는 경우가 많습니다.
Step 5: 가독성 향상과 인터페이스 설계에서는 시니어 개발자들이 이 복잡한 암호문들을 어떻게 '읽기 좋은 문장'으로 정리하는지, 그 기술적 노하우를 다룹니다.
Step 5: 가독성 향상과 인터페이스 설계 (Clean C++)
C++의 가독성이 떨어지는 주범은 std::shared_ptr<MyComplexControllerClass>와 같이 반복되는 긴 타입 이름입니다. 이를 해결하기 위해 '타입 별칭'과 '인터페이스 분리'를 적극적으로 사용해야 합니다.
1. using 키워드로 타입 별칭 만들기
파이썬이나 Go처럼 타입을 간결하게 만드는 첫 번째 단계입니다. 클래스 상단에 이를 선언하면 코드가 훨씬 깨끗해집니다.
#include <memory>
#include <vector>
class VideoFrame { /* ... */ };
// [암호 해독]: 복잡한 스마트 포인터 타입을 짧은 별칭으로 정의
// 보통 시니어들은 관례적으로 뒤에 'Ptr'을 붙여 스마트 포인터임을 명시합니다.
using VideoFramePtr = std::shared_ptr<VideoFrame>;
using VideoFrameUniquePtr = std::unique_ptr<VideoFrame>;
// 적용 전:
void process(std::shared_ptr<VideoFrame> frame);
// 적용 후: (훨씬 읽기 편해짐)
void process(VideoFramePtr frame);
2. 의존성 주입(DI)과 인터페이스 설계
로봇 프레임워크에서 "이미지 처리" 모듈을 만든다고 가정해 봅시다. 이때 구체적인 스마트 포인터 타입을 노출하지 않고 인터페이스를 설계하는 것이 고수의 핵심입니다.
// 1. 인터페이스 정의 (추상 클래스)
class IProcessor {
public:
virtual ~IProcessor() = default;
// 인터페이스에서는 주소값만 전달하는 & (Reference) 패턴을 주로 사용합니다.
virtual void execute(const VideoFrame& frame) = 0;
};
// 2. 실제 구현체
class EdgeDetector : public IProcessor {
public:
void execute(const VideoFrame& frame) override {
// 실제 연산 수행
}
};
// 3. 매니저 클래스 (스마트 포인터 관리)
class ProcessManager {
std::vector<VideoFramePtr> frame_queue;
public:
void run(IProcessor& processor) {
for (auto& frame : frame_queue) {
// [포인트]: 포인터 관리권은 매니저가 갖고,
// 실무자(processor)에게는 내용물(*frame)만 빌려줍니다.
processor.execute(*frame);
}
}
};
3. Pimpl 패턴: 컴파일 속도와 가독성 잡기
Drogon 라이브러리 내부를 보면 헤더 파일에 private 멤버가 거의 없고 class Impl; 같은 암호가 적혀 있는 경우가 있습니다. 이를 Pimpl (Pointer to Implementation) 패턴이라고 합니다.
// MyController.h (헤더 파일)
class MyController {
public:
MyController();
~MyController();
void doSomething();
private:
// [암호 해독]: 내부 구현은 감추고 포인터 하나만 둡니다.
// 이렇게 하면 헤더 파일이 매우 깨끗해지고, 수정 시 컴파일 시간이 단축됩니다.
struct Impl;
std::unique_ptr<Impl> pImpl;
};
4. Step 5 요약 가이드 (시니어의 코드 정리 기술)
| 기술 | 적용 전 (암호문) | 적용 후 (클린 코드) | 효과 |
|---|---|---|---|
| Type Alias | std::shared_ptr<Data> |
using DataPtr = ... |
가독성 비약적 향상 |
| Const Reference | void func(DataPtr p) |
void func(const Data& d) |
불필요한 참조 횟수 조절 방지 |
| Factory Method | new Object() |
Object::create() |
생성 로직 은닉 및 안전성 확보 |
| Auto Keyword | DataPtr p = ... |
auto p = ... |
타입 추론을 통한 코드 간결화 |
💡 마지막 조언: "좋은 C++ 코드는 Python처럼 읽혀야 한다"
C++이 어렵게 느껴지는 이유는 메모리 관리 문법이 비즈니스 로직(알고리즘)과 뒤섞여 있기 때문입니다. Step 5에서 배운 것처럼 using으로 타입을 숨기고, 인터페이스로 소유권 로직을 분리하면, 핵심 로직은 파이썬이나 Go처럼 간결하게 읽히게 됩니다.
🏁 종합 액션 플랜: 스마트 포인터 마스터하기
- 독점할 것인가? →
unique_ptr+std::move - 나눠 볼 것인가? →
shared_ptr(복사) - 함수에게 잠깐 빌려줄 것인가? →
*ptr전달 (Reference 인자) - 비동기로 예약할 것인가? →
[self = shared_from_this()]캡처 - 코드가 지저분한가? →
using별칭과 인터페이스 분리
이제 유튜브 영상에서 말한 "ROS를 걷어내고 직접 짜는 프레임워크"의 코드들이 단순한 암호가 아닌, 철저히 계산된 성능 최적화의 설계도로 보이실 겁니다.
지금까지 배운 내용을 바탕으로, 실제 Drogon이나 로봇 프로젝트의 특정 코드 파일을 다시 한번 열어보시겠어요? 예전보다 훨씬 많은 것이 보일 것입니다.
'C++' 카테고리의 다른 글
| [C++ 스마트포인터 시리즈 5] 스마트 포인터와 람다 캡처 (비동기 콜백 설계) (0) | 2026.01.01 |
|---|---|
| [C++ 스마트포인터 시리즈 4] 공유된 소유권 shared_ptr (Reference Counting) (0) | 2026.01.01 |
| [C++ 스마트포인터 시리즈 3] 독점적 소유 unique_ptr와 실전 파이프라인 (1) | 2026.01.01 |
| [C++ 스마트포인터 시리즈 2] 왜 내 코드는 암호가 되었나? (0) | 2026.01.01 |
| [C++ 스마트포인터 시리즈 1] ROS를 걷어내고 순수 C++로 구축하는 고성능 프로덕션 시스템 설계 가이드 (0) | 2026.01.01 |