복사 생성자와 이동 생성자
( 본 게시글은 작성자가 메모용으로 사용하는 용도임을 밝힙니다. 정보가 불확실할 수 있으니 참고 부탁드립니다 )
복사 생성자, 복사 대입 연산자
복사 생성자는 객체의 복사본을 만들기 위해 사용하는 생성자이다. 생성자와 소멸자처럼 클래스를 만들때 복사 생성자를 만들지 않으면 컴파일러가 알아서 생성해준다. 복사 대입 연산자는 같은 타입의 객체를 다른 객체에 값을 복사할때 사용한다. 복사 대입 연산자 또한 만들지 않아도 컴파일러가 알아서 생성해준다.



위의 Copy(const Copy& rhs) 함수가 복사 생성자의 형태이고, 밑의 함수가 복사 대입 연산자의 형태이다.
이후 밑에 Copy클래스의 객체 c를 만들고 밑에 추가로 객체 c1, c2를 만든다. 여기까지는 생성자가 각자 호출되며, 객체가 만들어졌음을 확인할 수 있다.
이후에 밑에 객체 c3가 생성되면서 객체 c1의 값을 동시에 초기화해주면 복사 생성자가 호출된다. 그리고 객체 c1에 객체 c2 값을 그대로 복사시키면 복사 생성자가 아닌 복사 대입 연산자가 호출된다. 이것이 복사 생성자와 복사 대입 연산자의 차이점이다. 객체가 생성됨과 동시에 객체를 복사하면 복사 생성자가 호출되고, 이미 생성되어있는 객체에 다른 객체를 복사하면 복사 대입 연산자가 호출된다.
예전 수업에서 얕은 복사와 깊은 복사라는 것을 배운 적이 있다. 얕은 복사는 복사를 할때 완전한 복사가 아닌 그 변수 혹은 멤버의 참조값만 복사하기 때문에, 얕은 복사는 독립적인 복사본을 만들 수 없는 것이 문제다 ( 서로 같은 주소를 가리키기 때문에, 얕은 복사후 다른 한쪽이 값이 변경되면 또다른 한쪽의 값또한 변경된다. 공유하게되는 셈 ).
이 얕은 복사의 문제점은 복사 생성자를 통해 해결할 수 있다.


객체 c를 만들고 p에 c를 복사한 후 p.SetData와 SetName으로 값을 저장후 출력해보면 c에 영향을 주지 않는 복사가 이뤄졌음을 볼 수 있다. 독립된 객체 c, p가 있고, 둘은 각각의 Data와 Name을 가지고 있는 것이다.
============================================================================
이동 생성자, 이동 대입 연산자
이동 연산자를 보기 전에 Lvalue와 Rvalue라는 개념을 알아보아야 한다. int a = 10;이라는 것을 두고 봤을때 Lvalue는 int a에 해당하는 부분으로 변수, 주소값, 클래스, 구조체 등 우리가 지금까지 봐왔던 변수가 있는 값이다. Rvalue는 10에 해당하는 부분으로 실체가 없는 일시적인 값이 존재하는 값이다. Lvalue가 식의 오른쪽 왼쪽 모두 올 수 있는 반면, Rvalue는 식의 오른쪽에만 올 수 있다.


이동 생성자의 형식은 다음과 같고, 이동 생성자는 rhs에 들어오는 객체의 데이터를 앞에 써져있는 객체로 복사하는데, 이 복사가 진행될때 메모리를 따로 할당하여 복사하지 않고, 참조값을 사용해 아예 데이터의 소유권을 넘긴다. 그렇기 때문에 복사 생성자보다 처리 속도가 더 빠르다.

이동 생성자도 복사 생성자와 비슷하게 객체가 생성될때 이동 생성자가 호출된다. 위의 Move studentName1("성현준")에서 성현준이 출력되고, 그 밑에 studentName2에 1의 값이 이동하면서 여기서 성현준이 출력되지만, 기존의 studentName1은 소멸된다. 그래서 저 상태로 컴파일을 누르면 에러가 난다 ( 2는 정상적으로 출력됨 ).


이동 대입 연산자도 복사 대입 연산자와 마찬가지로 만들어진 객체에 복사를 할때 이뤄지는데, 이동 생성자와 마찬가지로 복사 이후에 데이터를 넘겨준 객체는 소멸된다. 위에서 studentName1은 성현준, studentName2는 현준성을 출력하고 다시 각자 Getstr을 통해 성현준, 현준성을 출력하므로 여기까진 총 4줄이 출력될 것이다. 이후 studentName2 = move(studentName1)으로 이동하고 나서 다시 studentName1,studentName2의 Getstr을 출력하면 1은 소멸했으므로 역시 에러가 나고, 1을 주석처리하고 2를 출력해보면 위처럼 현준성이 아닌 성현준이 출력된다.
종합해보면 복사 연산자는 깊은 복사를 하며, 독립적인 객체의 복사본을 만들어주고, 이동 연산자는 얕은 복사를 하며, 데이터값을 복사하지만, 원본은 소멸된다고 볼 수 있다.