。공부 。

<C++> 복사생성자

kyoe 2007. 12. 4. 23:32
일반생성자는 객체를 제외한 여러타입의 데이터를 초기화 하기 위해 쓰이는데 복사생성자는 객체를 초기화하는데 쓰이는 생성자라 생각하면 쉽다.
생성자에도 디폴트 생성자가있듯 복사생성자에도 디폴트 복사생성자가 존재한다.

* 디폴트 복사 생성자 *
- 사용자 정의 복사 생성자가 없을때 자동 삽입된다.
- 멤버변수대 멤버변수의 복사를 수행
- 멤버변수의 타입과 갯수에 따라 달리 정의된다.
- 얉은 복사(?)

class Lee{      //Lee클래스
    int x,y;
public:
    Lee(int _x,int _y){
        x=_x;
        y=_y;
    }
   
    Lee(const Lee &a){ //디폴트 복사생성자(정의하지않으면 이러한형테로 복사생성자가 생성된다. )
        x=a.x;           
        y=a.y;
    }
};
int main(void){
    Lee a(10,20);
    Lee kyoe(L);
    return 0;
}

Lee 클래스 객체 a를 갖고 kyoe객체를 초기화 하고 있다 이때 객체로 초기화하기 때문에 복사생성자를 호출하게 되는데 디폴트복사생성자를 사용자가 직접 정의 하지 않았다면 디폴트 복사생성자가 호출된다. 디폴트복사생성자의 기본형테는 인자를 참조로 받고 참조받은 값을 사용자가가 수정하지 못하도록 const로 정의 한다. 참조받은 객체 a를 이용해 현재 정의되어있는 모든 멤버변수를 객체a의 멤버변수와 똑같이 초기화하는 역할을 한다.
하지만 디폴트복사생성자엔 한가지 문제점이 있다 변수를 동적할당한 객체를 갖고 다른객체를 초기화하면 컴파일 타임엔 에러가 발생하지 않지만 런타임 엔 에러가 발생하는것을 볼수있다. 만약 동적할당된 변수를 갖고있는 a라는 객체로 b라는 객체를 초기화하게 되면 a객체의 동적할당된 변수가 가르키는 값까지 복사를 하는것이아니라 주소값만을 복사를 하기 때문이다.
한메모리 공간에 여러개의 이름을 붙여주든 무슨 상관인가 하지만 객체소멸시엔 문제가 발생한다 스텍의 기본 법칙에 의해 늦게 생성된 객체 b의 값이 먼저 소멸하게 되는데 이때 메모리 공간에 할당되었던 값이 사라지게 된다 사라진 공간을 가르키고 있는 a객체를 소멸 할때 에러가 발생하게 되는데 이것을 방지하기 위에 우리는 메모리공간의 값까지 복사를 하는 깊은 복사를 필요로 한다.

* 깊은 복사 *
class apple{
    char *name;
    char *address;
    int number;
public:
    apple(char *_name,char *_address,int _number);
    apple(const apple& a);
    ~apple();
};

apple::apple(char *_name,char *_address,int _number){
    name=new char[strlen(_name)+1];
    strcpy(name,_name);
   
    address=new char[strlen(_address)+1];
    strcpy(address,_address);

    number=_number;
}

apple::apple(const apple &a){      //복사생성자
    name=new char[strlen(a.name)+1];   //a.name의 길이만큼 새로운메모리공간할당
    strcpy(name,a.name);      //할당된 메모리공간에 a.name값은 한문자씩 복사

    address=new char[strlen(a.address)+1];
    strcpy(address,a.address);

    number=a.number;      //정수형변수는 일반초기화하는것과 같다.
}

apple::~apple(){           //소멸자
    delete []name;         //메모리손실을 덜수있게 될수있음 꼭 해제시켜주자
    delete []address;
}

int main(void){
    apple aa("kyoe","tistory",1234);
    apple bb(aa);
    return 0;
}

기본적인건 디폴트복사생성자와 같다 여기서 유심히 봐야할건 변수를 동적할당한다는 것이다.
동적할당된 변수를 디폴트복사생성자로 초기화 하게되면 얉은 복사가 되기때문에  깊은복사의 형태로 복사형태를 바꾸는것이다. 객체를 참조형테로 받는것까진 같다 하지만 변수를 초기화 할때 값을 바로 대입해 넣지 않고 객체 a의 동적할당된 name의 길이만큼 힙영역에 메모리공간을 할당한다 이렇게 새로운 메모리공간이 힙영역에 할당이 되고 strcpy()함수를 이용해 새로이 할당된 메모리 공간에 a.name값을 복사하는 것이다.
이렇게 되면 서로다른 공간에 같은 값을 갖고 있으므로 초기화도 완벽하게 되었고 객체소멸시에도 에러가 발생하지 않는다 이런복사형태를 깊은복사라한다.