본문 바로가기
프로그래밍/C++

C++ 표준 컨테이너는 언제나 깊은 복사를 한다.

by bantomak 2025. 12. 6.
반응형

표준 컨테이너는 언제나 깊은 복사를 한다.

코드를 작성하다 보면 생각 없이 =(대입)을 사용하다가 실수하는 경우들이 종종 일어난다. std::list나 std::vector 같은 컨테이너 객체를 무심코 대입하다 보면 컨테이너의 원본이 아니라 복사된 객체를 수정하고 뭐가 문제인지 몰라 한참을 디버깅하는 경우 말이다.

 

이제는 확실하게 짚고 가보자. 정면으로 부딫히면 생각보다 두려운 존재는 없다.

std::list<int> a = b;   // 깊은 복사 (복사 생성자)
std::list<int> a;
a = b;                  // 깊은 복사 (복사 대입연산자)

우선, 한가지 명확한 사실은 C++의 표준 컨테이너를 대입하면  언제나 깊은 복사가 일어난다.

무조건 별개의 객체로 복사가 이뤄진다는 것이다. 이는 원본 객체를 안전하게 보호하고 복사된 객체를 자유롭게 다룰 수 있게 한다.

오른쪽이 임시 객체(rvalue)라면 move가 일어난다.

그렇다면 복사가 아니라 이동이 이뤄지는 경우는 언제일까? 이때는 대입하는 값이 임시 객체(rvalue)라면 이동이 수행된다.

struct MyObj {
    std::list<int> data;

    MyObj() = default;
    MyObj(const MyObj&) { std::cout << "copy ctor\n"; }
    MyObj(MyObj&&) { std::cout << "move ctor\n"; }
    MyObj& operator=(const MyObj&) { std::cout << "copy assign\n"; return *this; }
    MyObj& operator=(MyObj&&) { std::cout << "move assign\n"; return *this; }
};

MyObj a;
a = MyObj();

 

즉, 복사가 아니라 이동 대입이 호출된다.

MyObj a;
MyObj b;
b = std::move(a);

추가적인 경우로는

  • & 참조 타입으로 대입하는 경우
  • std::move를 사용해서 r-value로 변환하여 이동
std::list<int> d = std::move(c); // 이동 생성자
std::list<int>& e = d; // 이동 생성자
f = std::move(e); // 이동 대입 연산자

정리하자면

  • 표준 컨테이너는 대입시 언제나 깊은 복사를 수행한다. (원본이 아닌 복사본이 생성)
  • 오른쪽이 임시 객체(rvalue)라면 얕은 복사가 수행된다. (원본을 가져옴)

함께 읽으면 좋은 글

 

C# 얕은 복사, 깊은 복사에 대해서 알아보자

얕은 복사(Shallow Copy) 예시 코드Key와 Value가 그대로 복사됨Value가 만약 참조 타입이면, 복사본과 원본이 같은 인스턴스를 가리킴Dictionary Currencies = new(){ { "USD", new Currency("Dollar", 1.0m) }, { "EUR", new Cur

jettstream.tistory.com

 

C++ std::vector 사용시 push_back()과 emplace_back() 차이에 대해서

push_back() 이미 만들어진 객체를 복사 또는 이동해서 추가push_back은 이미 생성된 객체를 추가할 때 사용한다.내부적으로 복사 생성자 혹은 이동 생성자가 호출된다.std::vector v;std::string s = "Hello";v.p

jettstream.tistory.com

댓글