복사 생략(Copy Elision)은 '복사 회피'라고도 불리며, C++에서 가장 널리 사용되는 컴파일러 최적화 기법 중 하나입니다. 이 기법은 프로그램 실행 중 발생할 수 있는 불필요한 객체 복사를 제거하여 성능을 향상시킵니다. 현재 사용되는 대부분의 C++ 컴파일러는 기본적으로 이 복사 생략 기술을 지원하고 있습니다.
그럼 예제 코드를 통해 복사 생략이 실제로 어떻게 동작하는지 살펴보겠습니다.
예제 코드
#include <iostream>
using namespace std;
class MyClass {
public:
MyClass(const char* str = "\0") { //기본 생성자
cout << "Constructor called" << endl;
}
MyClass(const MyClass &my_cls) { //복사 생성자
cout << "Copy constructor called" << endl;
}
};
main() {
MyClass ob = "copy class object";
}실행 결과
Constructor called
왜 복사 생성자가 호출되지 않았을까?
위 실행 결과를 보면 복사 생성자가 호출되지 않고 기본 생성자만 호출된 것을 확인할 수 있습니다. 그 이유가 무엇일까요?
일반적으로 객체가 생성될 때, 임시 객체(temporary object)가 먼저 만들어진 후 이것이 실제 객체로 복사됩니다. 즉, 내부적으로 다음과 같이 동작한다고 볼 수 있습니다.
MyClass ob = "copy class object";
위 코드는 개념적으로 아래와 같이 해석될 수 있습니다.
MyClass ob = MyClass("copy class object");즉, 문자열 리터럴로 임시 객체가 생성되고, 그 객체가 다시 ob에 복사되는 과정이 필요해 보입니다. 하지만 C++ 컴파일러는 이러한 불필요한 복사 오버헤드를 자동으로 제거합니다. 컴파일러는 임시 객체를 거치지 않고 문자열 리터럴을 직접 사용해 ob를 한 번에 생성하도록 코드를 최적화하기 때문에, 복사 생성자가 호출되지 않는 것입니다.
정리
- 복사 생략(Copy Elision)은 불필요한 객체 복사를 방지하는 컴파일러 최적화 기법이다.
- C++17부터는 일부 경우(임시 객체 반환 등) 복사 생략이 표준에 따라 필수적으로 적용된다.
- 덕분에 개발자는 성능 저하 없이 값을 반환하거나 객체를 초기화하는 코드를 자연스럽게 작성할 수 있다.