본문 바로가기

카테고리 없음

코드 최적화 in C++

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::vectorstd::list 중 어느 것이 더 빠른가요?

A: std::vector는 연속된 메모리를 사용하므로 캐시 효율성이 높아 순차 접근이 빠릅니다. 반면, std::list는 삽입/삭제가 빠르지만 메모리 접근 비용이 큽니다.

Q: std::move를 언제 사용해야 하나요?

A: 객체를 더 이상 사용하지 않을 때(소유권 이전 시) std::move를 사용하면 불필요한 복사를 방지할 수 있습니다.

Q: inline 키워드는 언제 사용하나요?

A: 작은 함수의 호출 오버헤드를 줄이기 위해 inline을 사용하지만, 과도한 사용은 코드 크기를 증가시킬 수 있습니다.

Q: constexprconst의 차이점은?

A: constexpr은 컴파일 타임에 값을 계산할 수 있도록 보장하는 반면, const는 런타임 상수로만 사용할 수 있습니다.


 

이 외에도 프로파일링을 통해 성능 병목 지점 분석 후, 구체적인 최적화 적용이 중요합니다. 🚀