struct의 복사 (copy)

C/C++ 세계에는 복사와 지정(assignment)의 개념이 혼동되는 것이 흔하다.

Copy와 assignment의 차이를 혹여 이해하지 못하는 사람을 위하여 설명하면,

Copy는 새로운 개체를 만들고 그 개체에 복사하려는 개체의 내용물을 그대로 가져다 넣는 것이다. 따라서 copy가 되면 복사본과 원본은 개별적으로 다뤄질 수 있다. 다시 말해 원본을 건드렸다고 복사본의 내용이 바뀌거나 하지 않는다.

대신 assignment는 마치 원본의 pointer를 가리키는 또 다른 (address) 개체가 생겨나고 단지 address만 복사되었다고 보면 된다. 이 경우에는 원본과 복사본이 서로 의존성을 띄게 된다.

C 시절에는 struct의 복사에 대해서 의문이 많았는데, 그 때문에 주로 memory를 복사하는 방법으로 옮겼다. 이게 일종의 failsafe한 방법이니까.

문제는 struct에 pointer를 가지고 있거나 pointer에 준하는 것들 (vector/list 따위)이 들어있을 때인데, 이 때는 memory copy를 해도 되긴 하지만 그것은 해당 내용물의 변화 (소멸하거나 생성되거나)가 없을 때에나 의미가 있고 만일 해당 개체들이 소멸하거나 한다고 보면 나중에 문제를 일으킬 확률이 크다.

따라서 복사를 하는 것이 좋은지 아니면 원본의 주소만 가져다 쓰는 게 유리한지 잘 결정을 하는 것이 좋다. 대개 이게 잘 구분이 안되면 두고 두고 말썽을 일으키는 물건을 만들게 된다.

신기하게도 vector가 들어있는 struct를 return하면 내용물간 copy가 잘 일어나고 struct끼리 “=”로 복사를 시켜봐도 잘 된다. 이미 말했듯, 이 때는 memory 개체를 내가 따로 만들고 memory 내용도 강제 복사하고 하면 vector 때문에 문제가 생긴다.

이를테면 vector가 포함된 원본 a가 있고 내가 동일한 구조의 b의 memory를 할당한 뒤에 a의 내용물을 memory copy롤 b에 복사해넣었다 치면 struct의 내용물과 vector까지 복사가 되는 것 같지만 vector는 원본 vector의 주소만을 가져다 복사했기 때문에 얼핏 보기에 동일한 내용을 갖게끔 copy가 된 것 같지만, a의 vector 내용과 동일한 내용을 갖게 되고 (assign된 것 처럼), 만일 b를 소멸시키면 문제가 발생한다. 즉, a가 선언된 영역의 실행이 종료될 때 a가 소멸되고 이 때 a의 내용물인 vector도 정상적으로 소멸되어야 하는데, b가 소멸될 때 소멸되므로 최종적으로 2번 소멸되는 효과가 발생하기 때문이다.

개인적인 팁은..

1) 한번 정의되고 여기 저기서 참조되는 경우는 pointer를 쓰는 것이 좋다. 2) 한번 정의되고 계속해서 변화하면서 여기 저기서 참조되면 pointer가 좋다. 3) class를 자꾸 만들고 여기 저기서 타이핑을 덜하려고 변수를 잔뜩 만드는 스타일은 코드 관리가 힘들고 어떤 것이 복사되었고 어떤 것이 address를 가지고 있는지 구분도 힘들다. 이런 애들과 일하면 피곤하다.