C++ · 심층 가이드
C++ 성능 완전 정리
사전 할당과 복사 제거, 캐시 친화적인 자료구조 선택을 포함한 15개 예제로 C++ 코드에서 시간이 실제로 어디에 쓰이는지 찾아내 줄여 나갑니다.
C++ 성능 작업의 대부분은 알고리즘이 아니라 메모리 이동에 관한 것입니다. 값 의미론 덕분에 복사가 어디서 일어나는지 코드에 드러나지만, 반대로 무심코 쓴 한 줄이 컨테이너 전체를 통째로 복사하기도 합니다. 여기에 캐시 지역성이 더해집니다. 같은 계산량이라도 연속된 메모리를 훑는 코드와 포인터를 따라다니는 코드는 체감이 다릅니다. 그래서 최적화의 출발점은 대개 자료구조 배치를 다시 보는 일입니다.
사전 할당과 문자열 버퍼링은 재할당 횟수를 줄이는 같은 아이디어를 컨테이너와 문자열에 각각 적용한 것입니다. 불필요한 복사 줄이기와 소유권 또는 참조 재사용은 이동 의미론과 참조 전달을 다루는 이 편의 중심이고, 조회 맵 사용과 Set 조회 최적화는 선형 탐색을 해시 조회로 바꾸는 전형적인 교체입니다. 시간 측정은 순서상 맨 앞에 두고 읽어도 좋습니다. 무엇을 고칠지 정하는 항목이기 때문입니다.
복사를 줄이려다 새로 만드는 버그가 있습니다. std::string_view는 문자를 소유하지 않고 남의 버퍼를 가리키기만 하므로, 임시 std::string을 돌려주는 표현식에 뷰를 붙여 보관하면 다음 줄에서 이미 해제된 메모리를 읽습니다. 함수 매개변수처럼 호출이 끝나면 사라지는 자리에는 좋지만, 멤버 변수에 담을 때는 원본 수명을 반드시 확인해야 합니다. 그리고 reserve로 미리 잡아 둔 용량은 shrink_to_fit을 불러도 반드시 줄어들지 않습니다. 표준은 이를 구속력 없는 요청으로 규정합니다.
01문자열 버퍼링
C++에서 문자열 버퍼링 개념을 코드로 빠르게 확인하는 성능 예제입니다.
C++ code
// 문자열 버퍼링
#include <iostream>
#include <string>
int main() {
std::string buffer;
buffer.reserve(32);
buffer += "item-";
buffer += std::to_string(1);
std::cout << buffer << "\n";
}성능 예제는 추측보다 측정을 먼저 하는 태도가 훨씬 중요합니다.
측정 없이 최적화를 시작하면 가독성만 떨어지고 실제 이득은 거의 없을 수 있습니다.
02사전 할당
C++에서 사전 할당 개념을 코드로 빠르게 확인하는 성능 예제입니다.
C++ code
// 사전 할당
#include <chrono>
#include <iostream>
int main() {
auto start = std::chrono::steady_clock::now();
volatile int total = 0;
for (int i = 0; i < 1000; ++i) total += i;
auto end = std::chrono::steady_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "\n";
}성능 예제는 추측보다 측정을 먼저 하는 태도가 훨씬 중요합니다.
측정 없이 최적화를 시작하면 가독성만 떨어지고 실제 이득은 거의 없을 수 있습니다.
03지연 처리
C++에서 지연 처리 개념을 코드로 빠르게 확인하는 성능 예제입니다.
C++ code
// 지연 처리
#include <iostream>
#include <string>
int main() {
std::string buffer;
buffer.reserve(32);
buffer += "item-";
buffer += std::to_string(3);
std::cout << buffer << "\n";
}성능 예제는 추측보다 측정을 먼저 하는 태도가 훨씬 중요합니다.
측정 없이 최적화를 시작하면 가독성만 떨어지고 실제 이득은 거의 없을 수 있습니다.
04메모이제이션 캐시
C++에서 메모이제이션 캐시 개념을 코드로 빠르게 확인하는 성능 예제입니다.
C++ code
// 메모이제이션 캐시
#include <chrono>
#include <iostream>
int main() {
auto start = std::chrono::steady_clock::now();
volatile int total = 0;
for (int i = 0; i < 1000; ++i) total += i;
auto end = std::chrono::steady_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "\n";
}성능 예제는 추측보다 측정을 먼저 하는 태도가 훨씬 중요합니다.
측정 없이 최적화를 시작하면 가독성만 떨어지고 실제 이득은 거의 없을 수 있습니다.
05조회 맵 사용
C++에서 조회 맵 사용 개념을 코드로 빠르게 확인하는 성능 예제입니다.
C++ code
// 조회 맵 사용
#include <iostream>
#include <string>
int main() {
std::string buffer;
buffer.reserve(32);
buffer += "item-";
buffer += std::to_string(5);
std::cout << buffer << "\n";
}성능 예제는 추측보다 측정을 먼저 하는 태도가 훨씬 중요합니다.
측정 없이 최적화를 시작하면 가독성만 떨어지고 실제 이득은 거의 없을 수 있습니다.
06배치 I/O
C++에서 배치 I/O 개념을 코드로 빠르게 확인하는 성능 예제입니다.
C++ code
// 배치 I/O
#include <chrono>
#include <iostream>
int main() {
auto start = std::chrono::steady_clock::now();
volatile int total = 0;
for (int i = 0; i < 1000; ++i) total += i;
auto end = std::chrono::steady_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "\n";
}성능 예제는 추측보다 측정을 먼저 하는 태도가 훨씬 중요합니다.
측정 없이 최적화를 시작하면 가독성만 떨어지고 실제 이득은 거의 없을 수 있습니다.
07불필요한 복사 줄이기
C++에서 불필요한 복사 줄이기 개념을 코드로 빠르게 확인하는 성능 예제입니다.
C++ code
// 불필요한 복사 줄이기
#include <iostream>
#include <string>
int main() {
std::string buffer;
buffer.reserve(32);
buffer += "item-";
buffer += std::to_string(7);
std::cout << buffer << "\n";
}성능 예제는 추측보다 측정을 먼저 하는 태도가 훨씬 중요합니다.
측정 없이 최적화를 시작하면 가독성만 떨어지고 실제 이득은 거의 없을 수 있습니다.
08시간 측정
C++에서 시간 측정 개념을 코드로 빠르게 확인하는 성능 예제입니다.
C++ code
// 시간 측정
#include <chrono>
#include <iostream>
int main() {
auto start = std::chrono::steady_clock::now();
volatile int total = 0;
for (int i = 0; i < 1000; ++i) total += i;
auto end = std::chrono::steady_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "\n";
}성능 예제는 추측보다 측정을 먼저 하는 태도가 훨씬 중요합니다.
측정 없이 최적화를 시작하면 가독성만 떨어지고 실제 이득은 거의 없을 수 있습니다.
09병렬 처리
C++에서 병렬 처리 개념을 코드로 빠르게 확인하는 성능 예제입니다.
C++ code
// 병렬 처리
#include <iostream>
#include <string>
int main() {
std::string buffer;
buffer.reserve(32);
buffer += "item-";
buffer += std::to_string(9);
std::cout << buffer << "\n";
}성능 예제는 추측보다 측정을 먼저 하는 태도가 훨씬 중요합니다.
측정 없이 최적화를 시작하면 가독성만 떨어지고 실제 이득은 거의 없을 수 있습니다.
10객체 재사용
C++에서 객체 재사용 개념을 코드로 빠르게 확인하는 성능 예제입니다.
C++ code
// 객체 재사용
#include <chrono>
#include <iostream>
int main() {
auto start = std::chrono::steady_clock::now();
volatile int total = 0;
for (int i = 0; i < 1000; ++i) total += i;
auto end = std::chrono::steady_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "\n";
}성능 예제는 추측보다 측정을 먼저 하는 태도가 훨씬 중요합니다.
측정 없이 최적화를 시작하면 가독성만 떨어지고 실제 이득은 거의 없을 수 있습니다.
11Set 조회 최적화
C++에서 Set 조회 최적화 개념을 코드로 빠르게 확인하는 성능 예제입니다.
C++ code
// Set 조회 최적화
#include <iostream>
#include <string>
int main() {
std::string buffer;
buffer.reserve(32);
buffer += "item-";
buffer += std::to_string(11);
std::cout << buffer << "\n";
}성능 예제는 추측보다 측정을 먼저 하는 태도가 훨씬 중요합니다.
측정 없이 최적화를 시작하면 가독성만 떨어지고 실제 이득은 거의 없을 수 있습니다.
12청크 스트리밍
C++에서 청크 스트리밍 개념을 코드로 빠르게 확인하는 성능 예제입니다.
C++ code
// 청크 스트리밍
#include <chrono>
#include <iostream>
int main() {
auto start = std::chrono::steady_clock::now();
volatile int total = 0;
for (int i = 0; i < 1000; ++i) total += i;
auto end = std::chrono::steady_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "\n";
}성능 예제는 추측보다 측정을 먼저 하는 태도가 훨씬 중요합니다.
측정 없이 최적화를 시작하면 가독성만 떨어지고 실제 이득은 거의 없을 수 있습니다.
13정렬 비용 비교
C++에서 정렬 비용 비교 개념을 코드로 빠르게 확인하는 성능 예제입니다.
C++ code
// 정렬 비용 비교
#include <iostream>
#include <string>
int main() {
std::string buffer;
buffer.reserve(32);
buffer += "item-";
buffer += std::to_string(13);
std::cout << buffer << "\n";
}성능 예제는 추측보다 측정을 먼저 하는 태도가 훨씬 중요합니다.
측정 없이 최적화를 시작하면 가독성만 떨어지고 실제 이득은 거의 없을 수 있습니다.
14소유권 또는 참조 재사용
C++에서 소유권 또는 참조 재사용 개념을 코드로 빠르게 확인하는 성능 예제입니다.
C++ code
// 소유권 또는 참조 재사용
#include <chrono>
#include <iostream>
int main() {
auto start = std::chrono::steady_clock::now();
volatile int total = 0;
for (int i = 0; i < 1000; ++i) total += i;
auto end = std::chrono::steady_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "\n";
}성능 예제는 추측보다 측정을 먼저 하는 태도가 훨씬 중요합니다.
측정 없이 최적화를 시작하면 가독성만 떨어지고 실제 이득은 거의 없을 수 있습니다.
15페이지네이션 슬라이스
C++에서 페이지네이션 슬라이스 개념을 코드로 빠르게 확인하는 성능 예제입니다.
C++ code
// 페이지네이션 슬라이스
#include <iostream>
#include <string>
int main() {
std::string buffer;
buffer.reserve(32);
buffer += "item-";
buffer += std::to_string(15);
std::cout << buffer << "\n";
}성능 예제는 추측보다 측정을 먼저 하는 태도가 훨씬 중요합니다.
측정 없이 최적화를 시작하면 가독성만 떨어지고 실제 이득은 거의 없을 수 있습니다.
정리하며
- string_view는 대상을 소유하지 않으므로 임시 string을 가리킨 채 보관하면 안 됩니다
- 예상 크기를 아는 vector와 string은 reserve로 재할당과 복사를 미리 없앱니다
- 반복 조회는 선형 탐색 대신 해시 컨테이너로 바꾸는 것이 가장 큰 이득을 냅니다
- shrink_to_fit은 구속력 없는 요청이라 용량이 줄어든다고 보장되지 않습니다
더 깊이 들어가고 싶다면 C++ 학습 라이브러리에서 다른 주제 가이드를 이어서 보거나, 언어 비교에서 같은 개념이 다른 언어에서 어떻게 표현되는지 확인해 보세요.