TIL 2024/8/07

Sung Joo Lee·2024년 8월 7일

Shallow VS Deep

얕은 복사

#include <iostream>

class Shallow {

private:
	int* data;
public:
	Shallow(int d);//생성자
	Shallow(const Shallow& source);//복사 생성자 (객체 복사용)
	~Shallow();//소멸자
};

int main()
{

	Shallow obj1{ 100 };
	displayShallow(obj1);//복사 생성자 호출

	return 0;
}

Shallow::Shallow(int d) {
	data = new int;
	*data = d;
}

Shallow::~Shallow() {
	delete data;
	std::cout << "free storage" << std::endl;
}

//displayShallow() 정의 되어있다고 가정한다.
  • 위의 코드의 문제가 뭘까?
  1. obj1이 생성되며 heap에 동적 생성된 공간을 가리키는 포인터 obj1.data가 복사 생성자에 의해 매개변수 (객체)에 복사가 된다.
    1. 만약 매개변수가 s일 때 s.data의 값은 obj1.data의 값과 동일하다
  2. displayShallow(obj1)가 해제될 때 s.data가 해제가 된다. 즉 s.data가 가리키고 있던 heap 공간의 data가 해제가 되기 때문에 main의 객체 obj1의 data가 dangling pointer가 된다.

깊은복사

  • 포인터 주소를 복사하는 것이 아니라, 데이터를 복사하여 복사 생성

  • 복사 생성자가 새로운 힙 공간을 할당하여 동일한 데이터 생성

    #include <iostream>
    
    class Deep {
    private:
    	int* data;
    public:
    	Deep(int d);
    	Deep(const Deep& source);
    	~Deep();
    };
    
    int main() {
    
    	return 0;
    }
    
    Deep::Deep(int d) {
    	data = new int;
    	*data = d;
    }
    
    Deep :: ~Deep() {
    	delete data;
    	std::cout << "free storage" << std::endl;
    }
    
    Deep::Deep(const Deep& source) { //Deep 복사 생성자
    	data = new int;
    	*data = *source.data;
    }
  • 포인터를 복사하는 것이 아닌 데이터 또한 복사하기 때문에 이중 해제의 문제 해결 가능
    • 매개변수 객체가 다른 heap data 공간을 가리키기 때문에 dangling pointer가 발생하지 않는다.

생성자 위임을 이용한 깊은 복사

  • 복사 생성자도 생성자이기 때문에 위임을 사용 가능하다.
Deep :: Deep(const Deep& source){
				:Deep(*source.data)
{
}

복사 생성자 잘 사용하는 법

  • 포인터 타입의 멤버 변수가 존재할 때는 깊은 복사 생성자 직접 구현
    • 새로운 heap 공간을 할당하여 값을 복사해 두어야 한다는 것을 명심
  • STL/ smart pointer 사용
    • STL은 내부적으로 안전한 복사 생성자가 구현되어 있음
    • Smart pointer는 복사를 허용하지 않거나 참조되어 있는 동안은 해제하지 않음
profile
개발로그

0개의 댓글