Search

[C++] 복사 생성자의 매개변수로 레퍼런스를 사용해야 하는 이유

간단소개
C++에서 복사 생성자의 매개변수로 레퍼런스를 사용해야 하는 이유를 예제 코드와 함께 정리했습니다.
팔만코딩경 컨트리뷰터
ContributorNotionAccount
주제 / 분류
C++
Scrap
태그
9 more properties
목차

C++ 복사 생성자

복사 생성자는 객체의 복사가 이루어질 때 호출되는 생성자이다.
아래와 같은 클래스가 있다고 해보자.
class Rectangle { private: int width; int height; public: Rectangle(); // 기본 생성자 Rectangle(const Rectangle& src); // 복사 생성자 Rectangle& operator=(const Rectangle& src); // 복사 대입 연산자 ~Rectangle(); // 소멸자 }
C++
복사
그리고 복사 생성자는 보통 아래와 같이 복사 대입 연산자를 이용해서 구현한다.
// 복사 생성자 Rectangle::Rectangle(const Rectangle& src) { *this = rhs; // 복사 대입 연산자 호출 } // 복사 대입 연산자 Rectangle& Rectangle::operator=(const Rectangle& rhs) { if (this != &rhs) { this->width = rhs.width; this->height = rhs.height; } return (*this); }
C++
복사
하지만 왜 복사 생성자의 매개변수는 꼭 레퍼런스(&) 자료형으로 받아야 하는 걸까?
왜 아래와 같이 값으로 받으면 안되는 걸까?
// 매개변수를 레퍼런스가 아닌 값으로 받음 Rectangle(const Rectangle src) { *this = rhs; // 복사 대입 연산자 호출 }
C++
복사

복사 생성자의 매개변수를 값으로 받으면 안되는 이유

결론부터 말하면 복사 생성자의 매개변수를 값으로 받으면 무한 반복에 빠지기 때문이다.
아래와 같이 코드가 있다고 해보자.
// copy.cpp class Rectangle { private: int width; int height; public: Rectangle(int width, int height); Rectangle(const Rectangle src); }; Rectangle::Rectangle(int width, int height) { this->width = width; this->height = height; } Rectangle::Rectangle(const Rectangle src) { *this = src; } int main() { Rectangle r1(10, 20); Rectangle r2(r1); return 0; }
C++
복사
MacOS 환경에서 c++ 컴파일러로 컴파일을 시도하면 아래와 같은 에러가 표시된다.
copy.cpp:7:29: error: copy constructor must pass its first argument by reference Rectangle(const Rectangle src); ^ const & copy.cpp:15:38: error: copy constructor must pass its first argument by reference Rectangle::Rectangle(const Rectangle src) { ^ const & 2 errors generated.
C++
복사
즉, 컴파일러 차원에서도 복사 생성자는 반드시 레퍼런스로 넘겨야 한다고 말하고 있다.
그렇다면, 값으로 매개변수로 넘겨주었을 때 어떤 과정을 거치길래 무한 반복에 빠지는 것일까?
코드와 함께 정리해보면 아래와 같다.
1.
새로운 객체가 복사 생성자를 한다.
Rectangle r2(r1);
C++
복사
2.
복사 생성자에서는 매개변수로 자료형이 레퍼런스가 아닌 값으로 온 것을 확인한다.
Rectangle::Rectangle(const Rectangle src) { *this = src; }
C++
복사
3.
값으로 전달된 매개변수는 스택 영역에 복사해야 한다. 따라서 Rectangle 클래스를 복사하기 위해 Rectangle 클래스의 복사 생성자를 다시 호출한다.
// 2번의 복사 생성자에서 호출한 복사 생성자 Rectangle::Rectangle(const Rectangle src) { *this = src; }
C++
복사
4.
위의 과정이 반복해서 일어나기 때문에 무한 반복에 빠진다.
여기서 하나 더 검증해야 할 것이 있다.
매개변수로 값이 들어왔을 때 복사 생성자가 호출되는 지 확인해야 한다.
아래와 같이 코드를 작성했다.
// copy.cpp #include <iostream> class Rectangle { private: int width; int height; public: Rectangle(int width, int height); Rectangle(const Rectangle& src); Rectangle& operator=(const Rectangle& rhs); void print(const Rectangle obj); }; Rectangle::Rectangle(int width, int height) { this->width = width; this->height = height; } Rectangle::Rectangle(const Rectangle& src) { std::cout << "Copy Constructor" << std::endl; *this = src; } Rectangle& Rectangle::operator=(const Rectangle& rhs) { if (this != &rhs) { std::cout << "Copy Assignment Operator" << std::endl; this->width = rhs.width; this->height = rhs.height; } return (*this); } void Rectangle::print(const Rectangle obj) { std::cout << "Width: " << obj.width << std::endl; std::cout << "Height: " << obj.height << std::endl; } int main() { Rectangle r1(10, 20); r1.print(r1); return 0; }
C++
복사
c++ 컴파일러로 컴파일 후 출력한 결과는 아래와 같다.
Copy Constructor Copy Assignment Operator Width: 10 Height: 20
Plain Text
복사
따라서 복사 생성자의 매개변수는 반드시 값이 아닌 레퍼런스로 받아야 한다는 결론을 내릴 수 있다.

참고자료