[C/C++]Shallow Copy & Deep Copy

HW·2024년 1월 18일
0

C/C++

목록 보기
5/5
post-thumbnail

서론

C++에서 얉은 복사와 깊은 복사를 알아봅니다.

본론

C++에는 2가지 방법으로 변수 초기화 할 수 있습니다.

int main (){
	int a = 10; //C 스타일 초기화
    int b(10); //C++ 스타일 초기화
    std::cout << a << std::endl; //10
    std::cout << b << std::endl; //10
}

ab 모두 10을 출력합니다.
그럼 객체도 두 가지 형태가 가능할것 같은데요.

class data{
private:
    int value;
public:
    data(int param){
        value=param;  //간단한 생성자
    }
    void output(){
        cout<<value<<endl;
    }
};
int main(){
    data a(10); //C++ 스타일 초기화
    data b=10; //C 스타일 초기화
    
    a.output(); // 10
    b.output(); // 10
    return 0;
}

다음과 같이 C, C++ 초기화 스타일 모두 10을 출력합니다.
다만 객체 생성에서의 C 스타일은
암시적으로 컴파일 과정에서 data b(10)로 변환되기 때문에
두 가지 형태가 동일하다고 볼 수 없습니다.

디폴드 복사 생성자 & 얕은 복사

class data{
private:
    char str[100];
public:
    data (char *param){ //생성자는 char* 자료형만 받는다.
        strcpy (str,  param);
    }
    void print(){
        std::cout << str << std::endl;
    }
};


int main () {

    data a ("아 그거 뭐더라");
    data b (a); //char* 자료형만 받는 생성자에 data 객체를 넣는다면???

    a.print(); //아 그거 뭐더라
    b.print(); //아 그거 뭐더라   

}

data 클래스는 char* 자료형과 분명히 다르죠.
data 클래스는 data 클래스를 자료형으로 받는
생성자 함수를 초기화 한적이 없음에도 불구하고
생성자 함수가 자동으로 삽입 되었습니다.

이렇게 자동으로 만들어지는 생성자를 디폴트 복사 생성자라고 합니다.

자기 자신과 같은 형태의 객체를 받는 것을 복사 생성자라고 합니다.

class data{
private:
    char *name;     
    char *velog; 
    int number;
public:
    data(char *_name, char* _velog, int _number){
        name = new char[strlen(_name)+1];
        strcpy(name,_name);
        velog = new char[strlen(_velog)+1];
        strcpy(velog,_velog);
        number = _number;
    } 
    void print(){
        std::cout<<name<<std::endl;
        std::cout<<velog<<std::endl;
        std::cout<<number<<std::endl;
    }
    void modify(char *val){
        strcpy(name,val);
    }
    ~data(){
        delete []name;
        delete []velog;
    }  
};
int main(){
    data *a = new data("HW","아 그거 뭐더라",20);
    data b(*a);
    a->print(); // HW "아 그거 뭐더라" 20
    a->modify("WH");

    b.print(); // WH "아 그거 뭐더라" 20
    delete a; 
    
    
    b.print(); 	//�~��V
                //20
                //free(): double free detected in tcache 2
                //Aborted (core dumped)
    
    return 0;
}

디폴트 복사 생성자는 직접 값을 복사하는 것이 아니라,
'참조' 하기 때문에 클래스가 실제로 데이터를 가지고 있는 것이 아닙니다.

이를 얕은 복사라고 합니다.

깊은 복사

깊은 복사는 참조값의 복사 대신 대신 참조된 객체 자체 복사라고 생각하면 됩니다.
얕은 복사와 달리 객체가 가진 모든 멤버를 복사합니다.

깊은 복사는 새로이 동적할당을 받고, 원본의 데이터를 복사합니다.

깊은 복사를 하기 위해선, 직접 복사 생성자를 정의해야 합니다.

class data{
private:
 char *name;
 char *velog;
 int number;
public:
 data(char *_name, char* _velog, int _number){
 name = new char[strlen(_name)+1];
 strcpy(name,_name);
 velog = new char[strlen(_velog)+1];
 strcpy(velog,_velog);
 number = _number;
 }
 data(const data& object){ // Copy Constructor로 사용할 수 있도록 매개변수를 const로 설정
 name = new char[strlen(object.name)+1];
 strcpy(name,object.name);

 velog = new char[strlen(object.velog)+1];
 strcpy(velog,object.velog);
 
 number = object.number;
 }
 void print(){
 std::cout<<name<<std::endl;
 std::cout<<velog<<std::endl;
 std::cout<<number<<std::endl;
 }
 void modify(char *val){
 strcpy(name,val);
 }
 ~data(){
 delete []name;
 delete []velog;
 }
};
int main(){
    data *a = new data("HW","아 그거 뭐더라",21);

    data b(*a);
    a->print(); //HW
				//아 그거 뭐더라
                //21
    delete a;
    b.print();	//HW
				//아 그거 뭐더라
                //21

}

결론

얕은 복사는 기본적으로 참조를 통해 객체를 복사하므로
동일한 데이터를 공유하게 됩니다.

반면, 깊은 복사는 새로운 메모리를 할당하여
데이터를 복사하므로 원본 객체의 변경이 복사본에 영향을 미치지 않습니다.

특히, 객체가 동적으로 할당된 메모리를 가지고 있을 때는
깊은 복사가 중요하며, 이를 위해 직접 복사 생성자를 정의해야 합니다.
또한, 디폴트 복사 생성자는 얕은 복사를 수행하므로 주의가 필요합니다.

올바른 객체 복사 방법을 선택하고 이해하면
메모리 관리와 프로그램 안정성을 높일 수 있습니다.

profile
예술융합형 개발자🎥

0개의 댓글