복사 생성자 : http://huiyu.tistory.com/341
*디폴트 복사 생성자는 멤버 대 멤버의 복사를 진행한다. 이러한 방식의 복사를 가리켜 '얕은 복사'라 하는데, 이는 멤버변수가 힙의 메모리 공간을 참조하는 경우에 문제가 된다.
*디폴트 복사 생성자의 문제점
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include <iostream> #include <cstring> using namespace std; class Person { private: char * name; int age; public: Person(char * myname, int myage) { int len = strlen(myname) + 1; name = new char[len]; strcpyt(name, myname); age = myage; } void ShowPersonInfo() const { cout << "이름 : " << name << endl; cout << "나이 : " << age << endl; } ~Person() { delete []name; cout<<"called destructor!"<<endl; } }; int main(void) { Person man1("Lee dong woo", 29); Person man2 = man1; man1.ShowPersonInfo(); man2.ShowPersonInfo(); return 0; } | cs |
이름 : Lee dong woo
-> 위의 실행결과에서 주목할 부분은 문자열 "called destructor!"가 단 한번만 호출되었다는 점이다.
두개의 객체를 생성했으므로, 소멸자도 두 번 호출되어야 하는데, 실행결과를 보면 한번만 호출되고 있다.
Person man2 = man1;
디폴트 복사 생성자는 멤버 대 멤버를 단순히 복사만 하므로, 다음의 구조를 띄게 된다.
->단순 복사를 진행하므로 하나의 문자열을 두 개의 객체가 동시에 참조하는 꼴을 만들고 있다.
이로 인해 객체의 소멸과정에서 문제가 발생한다.
man2객체가 먼저 소멸된 상황을 가정해보자, man2가 소멸시에 소멸자가 호출되면서 다음 문장도 실행된다.
delete [] name;
객체 man2의 소멸로 인해 다음과 같은 상황에 놓이게 된다.
이제 남아있는 man1객체가 소멸되면서 man1의 소멸자가 실행되어야 한다.
그러나 man1객체의 멤버 name이 참조하는 문자열은 이미 소멸된 상태이다. 조금 전 man2의 소멸자가 호출되면서 소멸시켜버렸다.
* 이미 지워진 문자열을 대상으로 delete 연산을 하기 때문에 문제가 된다. 따라서 복사 생성자를 정의할 땐 이러한 문제가 발생하지 않도록 신경써야한다.
*'깊은복사'를 위한 복사 생성자 정의
1 2 3 4 5 | Person (const Person& copy) : age(copy.age) { name = new char[strlen(copy.name)+1]; strcpy(name, copy.name); } | cs |
- 멤버 변수 age의 멤버 대 멤버 복사
- 메모리 공간 할당후 문자열 복사, 그리고 할당된 메모리의 주소값을 멤버 name에 저장
[참고자료]
윤성우의 열혈 C++프로그래밍 05-2 '깊은 복사'와 '얕은 복사'
'Software Development > C, C++' 카테고리의 다른 글
[C++] const, friend 키워드 (0) | 2018.12.30 |
---|---|
[C++] 복사 생성자의 호출시점 (1) | 2018.12.29 |
[C++] 복사 생성자(Copy Constructor) (0) | 2018.12.18 |
[C++] this 포인터 (0) | 2018.12.16 |
[C++] 생성자(Constructor)와 소멸자(Destructor) (0) | 2018.12.16 |