본문 바로가기

Language/C++

복사 생성자(얕은 복사)

복사 생성자는 말그대로 복사를 하기위한 함수이다. 물론 묵시적인 호출로 복사가 이루어 지지만 객체 끼리의 복사는 디폴트 복사 생성자로만 복사를 할수 있는 부분이 한정되어있다.

class Point
{
    int x, y;
public:
    Point(int _x,int _y)//복사하는 대상의 직접 접근이 불가능하다.
    {
        x = _x;
        y = _y;
    }
    Point(const Point& p)//복사하는 대상의 직접 접근이 가능하다.
    {
        x = p.x;
        y = p.y;
    }
    void ShowData()
    {
        cout<<x<<' '<<y<<endl;
    }
};

int main()
{
    Point p1(10,20);
    Point p2(p1);

    p1.ShowData();

    return 0;
}
매개변수가 레퍼런스로 참조 하는것을 알수있다. 또한, 참조된 객체를 말그대로 참조만 할뿐
변경을 하지 않을꺼기 때문에 const 키워드도 함께^^ 이는 디폴트 복사 생성자도 동일한 모양을 갖는다.

하지만...
위의 복사 생성자를 기제 하지 않더라도 에러가 나지 않는다. 이는 컴파일러에 의해서 묵시적으로 제공이 되어 호출이 된다.
기본적으로 디폴트라는 이름으로 제공되는 생성자, 소멸자 함수와 같이 아무런 작업을 하지 않는게 아니라 멤버 대 멤버로
복사를 할수 있게 디폴트함수로 제공이 된다는 것이다.

이를 얕은 복사라고 한다.

얕은 복사....왜 얕은 복사라고 할까. 얕은 복사의 치명적에 대한 소스는 다음과 같다.

class Person
{
    char *name;
    char *phone;
    int age;
public:
    Person(char* _name,char* _phone, int _age);
    Person(Person& p)//디폴트 복사 생성자도 동일하다.
    {
        name = p.mane;
        phone = p.phone;
        age = p.age;
    }
    ~Person();
    void ShowData();
};
Person::Person(char* _name, char* _phone, int _age)
{
    name = new char[strlen(_name)+1];
    strcpy(name, _name);

    phone = new char[strlen(_phone)+1];
    strcpy(phone, _phone);

    age = _age;
}

Person::~Person()
{
    delete []name;
    delete []phone;
}

void Person::ShowData()
{
    cout<<"name : "<<name<<endl;
    cout<<"phone: "<<phone<<endl;
    cout<<"age : "<<age<<endl;
}

int main()
{
    Person p1("KIM","013-333-555",22);
    Person p2 = p1;//묵시적으로 Person p2(p1);로 변환된다.

    return 0;
}

현재 이 코드는 런타임 에러를 이르킨다. 그 이유는 생성시도, 출력에도 문제가 없지만
소멸자 함수가 호출되면서 문제가 생기게 된다. 이유는 동적으로 할당된 name과 phone의 heap 에
있는 메모리주소를 p1과 p2가 공유를 하게 되는데(복사 생성자는 포인터의 주소값만 복사를 하게 된다.)
그 부분에서 p2의 소멸자가 (소멸의 순서는 생성의 순서의 완전 역순이다. 이유는 스택메모리의 특성을 반영
하기 때문이다!^^)호출되면서 heap에 있는 메모리를 해제 해버리기 때문에 p1이 소멸시켜야할 메모리가 사라
지기 때문이다. 이러한 형태를 '얕은 복사'라한다. 디폴트 복사 생성자는 얕은 복사를 호출한다.^^
그렇기 때문에 멤버가 동적할당을 하게된다면, 소멸자에 메모리 해제뿐 아니라 깊은 복사를 할수 있도록
복사생성자를 제공해줘야 한다.