얕은 복사와 깊은 복사
이전 섹션에서 설명한 복사 생성자의 예인 Circle 클래스에서 복사 전략은 시스템 기본 전략과 일치합니다. 즉, 원본 개체의 멤버가 새 개체의 해당 멤버에 순차적으로 복사됩니다. 이 경우 왜 우리는 여전히 그것을 직접 정의하고 싶습니까? 그 이유는 이렇게 간단한 방법으로 모든 상황을 단순히 초기화하면 필연적으로 다양한 상황에서 문제가 발생할 수 있기 때문입니다.
예를 들어 방금 Circle 클래스에서 멤버 변수에 포인터 멤버를 추가하고 초기화 중에 메모리를 동적으로 할당해야 한다면 보안상 큰 위험이 따릅니다. 코드는 다음과 같습니다.
/************************************//Des: C++ 튜토리얼 지원 프로그램//저자:Huang //복사권:www.dotcpp.com//날짜:2017/8/26******************************** ** ******/#include<iostream>#include<Cstring>usingnamespacestd;#definePI3.1415classCircle{private:doubleR;char*str;public:Circle(doubleR,char*str);~Circle(); );doublegirth();};원::~Circle(){delete[]str;}원::Circle(doubleR,char*str){cout<<Constructor<<endl;this->R=R ;this ->str=newchar[strlen(str)+1];strcpy(this->str,str);cout<<this->R<<<<this->str<<endl;}doubleCircle::area () {returnPI*R*R;}doubleCircle::girth(){return2*PI*R;}intmain(){CircleA(5,NO.1Oldclass);CircleB(A);return0;}
확인하기 위해 Circle 클래스에서 포인터 멤버를 추가하고 사용자 정의 복사 생성자 없이 생성자에서 이를 초기화했습니다. 그런 다음 주 함수에서 Circle B(A); 문장은 A 객체를 B 객체에 할당하고 기본 생성된 복사 생성자를 호출합니다. 프로그램은 아래와 같이 오류를 보고합니다.
실제 이유는 기본 복사 생성자가 데이터 할당만 수행하고 포인터용 메모리 공간을 열 수 없기 때문입니다. 이는 다음 코드와 동일합니다.
이->str=str;
따라서 본질적으로 두 개의 포인터는 힙 공간을 가리킵니다. 우리의 원래 의도와는 어긋나더군요. 그런 다음 프로그램이 끝날 때 두 개체가 재활용되면 해당 소멸자가 이 메모리 공간을 해제하기 위해 호출됩니다. 두 개체를 두 번 호출해야 하므로, 즉 두 번 삭제하면 오류가 발생합니다!
따라서 클래스에 포인터 유형이 있는 경우 기본 복사 생성자 메서드에 의존하는 것은 더 이상 우리의 요구를 충족할 수 없습니다. 데이터를 복사할 수 있을 뿐만 아니라 멤버에 대한 메모리 공간도 할당할 수 있는 특정 복사 생성자를 정의해야 합니다. 딥 카피(deep copy)라고도 불리는 실제 카피를 달성하기 위한 이것이 딥 카피 생성자 입니다.
딥 카피 생성자 구현:
#include<iostream>#include<Cstring>usingnamespacestd;#definePI3.1415classCircle{private:doubleR;char*str;public:Circle(doubleR,char*str);Circle(Circle&A);~Circle();doublerea(); doublegirth();};원::~원(){delete[]str;cout<<CallDestructor<<endl;}원::원(원&A){cout<<CopyConstructor<<endl;this->R=AR ;this->str=newchar[strlen(A.str)+1];strcpy(this->str,A.str);}Circle::Circle(doubleR,char*str){cout<<생성자<<endl ;this->R=R;this->str=newchar[strlen(str)+1];strcpy(this->str,str);}doubleCircle::area(){returnPI*R*R;}doubleCircle: :girth(){return2*PI*R;}intmain(){CircleA(5,NO.1Oldclass);CircleB(A);return0;}
구현 원리는 매개변수가 있는 생성자와 유사합니다. 완전한 복사를 완료하기 위해 할당 전에 충분한 메모리 공간이 열립니다. 이해하시고 컴퓨터에서 시도해 보세요!