title: “이번 주의 팁 #24: 복사, 축약” layout: tips sidenav: side-nav-tips.html published: true permalink: tips/24 type: markdown order: “024” —
원래 TotW #24로 2012년 11월 26일 게시됨
작성: Titus Winters (titus@google.com) 및 Chandler Carruth (chandlerc@google.com)
“다른 사람을 따라 하는 것은 필요하지만, 자신을 따라 하는 것은 비참하다.” - 파블로 피카소
참고: 이름 계산과 복사 vs. 이동에 대한 지침은 TotW #55 및 TotW #77을 참조하세요.
이름 하나면 복사 없음, 이름 두 개면 복사 두 번
어떤 스코프 내에서 복사가 발생하는지(또는 RVO(Return Value Optimization)가 발생하는 경우 포함)를 평가할 때는 데이터가 참조하는 이름의 수를 확인하세요.
어떤 시점에서든 데이터에 대해 두 개의 활성 이름이 존재하면, 데이터 복사가 두 번 발생합니다. 대략적으로, 컴파일러는 이 외의 경우 복사를 생략(또는 생략해야) 합니다.
STL 컨테이너의 이동 의미론(C++11로 전환되면서 자동으로 도입됨)과 컴파일러의 복사 생성자 생략 기능 덕분에, 이 규칙은 복사 횟수의 하한선뿐만 아니라 보장으로도 빠르게 수렴하고 있습니다. 벤치마크에서 더 많은 복사가 발생하는 것을 발견했다면, 이는 대부분 컴파일러 버그일 가능성이 높습니다. 컴파일러의 수정이 필요할 수 있습니다.
따라서 실행 중 특정 시점에 데이터에 대해 두 개의 이름을 도입하면 복사가 발생할 수 있습니다. 반대로, 데이터를 참조할 수 있는 이름의 도입을 피하면, 복사를 제거하려는 컴파일러의 최적화를 돕게 됩니다.
예제
이 규칙이 실제로 어떻게 작동하는지 몇 가지 예제를 살펴보겠습니다:
std::string build();
std::string foo(std::string arg) {
return arg; // 복사 없음: 데이터 “arg”에 대한 이름은 하나뿐.
}
void bar() {
std::string local = build(); // 단일 인스턴스: 이름도 하나만 존재
// 복사 없음: 참조는 복사를 발생시키지 않음
std::string& local_ref = local;
// 복사 1회 발생: 이제 두 개의 이름이 동일한 데이터를 가리킴
std::string second = foo(local);
}
대부분의 경우 이러한 내용은 중요하지 않습니다. 복사와 성능을 걱정하기보다는 코드의 가독성과 일관성을 확보하는 것이 훨씬 중요합니다. 항상 그렇듯이, 최적화에 앞서 프로파일링하세요. 그러나 새 코드를 작성하는 경우, 반환 값을 제공하는 깨끗하고 일관된 API를 제공할 수 있다면, 복사를 수행할 것처럼 보이는 코드를 간과하지 마세요. 10년 전 C++에서 배운 복사에 대한 모든 것은 잘못되었습니다.