C++

얕은 복사 VS 깊은 복사

monstro 2024. 4. 21. 20:21
728x90
반응형

본격적인 내용에 들어가기에 앞서 '복사'란 무엇일까요?

 

게임을 만들 때, 같은 몬스터들을 하나하나 새로 만드는 것보다는

하나의 몬스터를 만들고 그 몬스터를 복사하는 것이 훨씬 더 효율적일 것입니다.

 

복사도 이와 같은 개념으로 적용됩니다.

복사도 마찬가지로 같은 타입의 인스턴스를 일일이 새로 만들기 보다는 복사하는 것이 효율적입니다.

 

그렇다면 복사는 복사인데 얕은 복사와 깊은 복사는 왜 구분되는 것이고, 또 차이는 무엇일까요?

한번 알아보도록 하겠습니다.

 

1) 얕은 복사

Pet 클래스

 

Knight 클래스

 

main 스레드

 

위와 같이 구성된 코드를 실행시키면,

 

 

위와 같은 실행결과를 확인할 수 있습니다.

그런데 결과가 조금 이상합니다.

우리는 어찌 되었든, 두 개의 Knight 인스턴스를 만들었고 결과적으로 2개의 Pet 인스턴스가 동적할당되어야 합니다.

그러나 생성자는 하나만 호출되었고, 소멸자는 2개가 호출되었습니다.

 

이러한 이유가 발생한 원인은 메모리를 보면 확실히 알 수 있습니다.

 

디버그 모드에서 확인한 메모리

 

두 개의 Knight 인스턴스가 갖고 있는 _pet가 같은 주소를 참조하고 있습니다.

이해하기 쉽게 그림으로 설명드리자면, 

 

아래의 k1은 k2로 봐주세요

 

위와 같은 상황이 발생한 것입니다.

 

C++ 컴파일러는 따로 명시하지 않으면 복사 생성자를 자동으로 명시하게 되는데, 이는 얕은 복사의 역할을 수행합니다.

그리고 얕은 복사는 사본이 원본의 데이터를 그대로 복사하여 갖게 되는 것을 의미합니다.

 

복사 비용은 많이 소모되지 않지만, 문제는 원본이 참조하고 있는 경우에 발생합니다.

실행결과로 볼 수 있듯이,  소멸자가 2번 호출되었다는 것을 알 수 있습니다.

이처럼 얕은 복사는 저렴한 복사 비용을 갖고 있지만, 참조하고 있는 경우에는 심각한 문제를 발생시킬 수 있습니다.

 

 

2) 깊은 복사

이제는 깊은 복사에 대해서 알아보겠습니다.

이번에는 Knight 클래스만을 수정하도록 하겠습니다.

 

 

위의 코드를 실행시키면 다음과 같은 결과를 얻게 됩니다.

 

 

두 개의 생성자와 두 개의 소멸자가 생성되었습니다.

더 자세한 정보를 알아보기 위해서 메모리를 확인해보면,

 

 

두 개의 Knight 클래스의 인스턴스가 갖고있는 _pet이 서로 다른 주소를 참조하고 있음을 알 수 있습니다.

이와 같은 복사를 깊은 복사라고 합니다.

 

그림으로는 다음과 같이 설명할 수 있습니다.

 

 

위와 같이 깊은 복사는 원본 인스턴스를 복사하여 다른 인스턴스를 새로 만드는 것을 의미합니다.

이때 깊은 복사를 사용하기 위해서는 반드시 복사 생성자를 명시해주어야 합니다.

 

복사 비용이 많이 소모되지만, 그만큼 안전하게 사용이 가능하다는 이점이 있습니다.

 

3) 정리

-얕은 복사

  • 장점 : 복사 비용이 적다
  • 단점 : 참조까지 복사해버리는 문제가 있다

-깊은 복사

  • 장점 : 안전한 복사가 가능하다
  • 단점 : 복사 비용이 높다

정리하자면 위와 같습니다.

얕은 복사와 깊은 복사 둘 다 장점과 단점이 있습니다.

따라서 상황에 맞게 효율적으로 골라 사용하시면 되겠습니다.

728x90
반응형

'C++' 카테고리의 다른 글

iterator(반복자)  (0) 2024.04.29
오른값 참조  (0) 2024.04.22
C++의 캐스팅 - const_cast  (0) 2024.04.15
C++의 캐스팅 - reinterpret_cast  (0) 2024.04.14
C++의 캐스팅 - dynamic_cast  (0) 2024.04.14