C++ 코드 최적화는 실행 속도와 메모리 사용량을 줄이고 유지보수성을 향상시키는 중요한 과정입니다. 주요 최적화 기법을 살펴보겠습니다.
컴파일러 최적화 활용
- -O2, -O3 등의 최적화 옵션 사용 (g++ -O2 mycode.cpp -o myprogram)
- -march=native 플래그로 CPU 아키텍처에 맞게 최적화
데이터 구조 및 알고리즘 개선
- 적절한 컨테이너 선택 (std::vector vs std::list)
- 불필요한 복사 연산 제거 (std::move, std::swap)
- 시간 복잡도 고려하여 최적의 알고리즘 사용
메모리 최적화
- 동적 할당 최소화 (std::vector::reserve() 사용)
- 스마트 포인터 (std::unique_ptr, std::shared_ptr) 활용
- 캐시 친화적인 데이터 구조 설계
루프 최적화
- 불필요한 연산 제거 (루프 내 조건문 최소화)
- 반복문 언롤링 (Unrolling) 적용
- std::for_each, std::transform 같은 STL 함수 사용
// 불필요한 연산 제거 예제
for (int i = 0; i < vec.size(); i++) { // ❌ 비효율적인 코드
vec[i] = vec[i] * 2;
}
// 최적화된 코드
size_t n = vec.size();
for (size_t i = 0; i < n; i++) { // ✅ size() 호출 최소화
vec[i] *= 2;
}
// 반복문 언롤링 예제
for (size_t i = 0; i < n; i += 4) {
vec[i] *= 2;
vec[i + 1] *= 2;
vec[i + 2] *= 2;
vec[i + 3] *= 2;
}
함수 최적화
- 인라인 함수 (inline) 사용
- 함수 호출 최소화 (반복 호출되는 함수는 변수에 저장)
inline int square(int x) { return x * x; } // 인라인 함수
// 람다 함수 사용
auto square = [](int x) { return x * x; };
멀티스레딩 활용
- std::thread, std::async로 병렬 처리
- OpenMP, CUDA 같은 병렬 프로그래밍 기법 적용
#include <thread>
void task() { /* 작업 수행 */ }
std::thread t1(task), t2(task);
t1.join(); t2.join();
#include <vector>
#include <future>
std::vector<int> parallel_square(std::vector<int>& data) {
std::vector<std::future<int>> futures;
for (int& num : data) {
futures.push_back(std::async(std::launch::async, [num]() { return num * num; }));
}
std::vector<int> results;
for (auto& f : futures) {
results.push_back(f.get());
}
return results;
}
불필요한 객체 복사 방지
- const & 참조 사용
- std::move를 이용한 이동 연산 최적화
void process(const std::string& str); // 복사 방지
std::string data = "example";
process(std::move(data)); // 이동 최적화
컴파일 타임 최적화 (템플릿, constexpr)
- constexpr을 사용하여 컴파일 시간 계산 수행
constexpr int factorial(int n) { return (n <= 1) ? 1 : (n * factorial(n - 1)); }
template <int N>
struct Factorial {
static constexpr int value = N * Factorial<N - 1>::value;
};
template <>
struct Factorial<0> {
static constexpr int value = 1;
};
constexpr int fact5 = Factorial<5>::value; // 120
Q&A
Q: std::vector와 std::list 중 어느 것이 더 빠른가요?
A: std::vector는 연속된 메모리를 사용하므로 캐시 효율성이 높아 순차 접근이 빠릅니다. 반면, std::list는 삽입/삭제가 빠르지만 메모리 접근 비용이 큽니다.
Q: std::move를 언제 사용해야 하나요?
A: 객체를 더 이상 사용하지 않을 때(소유권 이전 시) std::move를 사용하면 불필요한 복사를 방지할 수 있습니다.
Q: inline 키워드는 언제 사용하나요?
A: 작은 함수의 호출 오버헤드를 줄이기 위해 inline을 사용하지만, 과도한 사용은 코드 크기를 증가시킬 수 있습니다.
Q: constexpr과 const의 차이점은?
A: constexpr은 컴파일 타임에 값을 계산할 수 있도록 보장하는 반면, const는 런타임 상수로만 사용할 수 있습니다.
이 외에도 프로파일링을 통해 성능 병목 지점 분석 후, 구체적인 최적화 적용이 중요합니다. 🚀