복사 생성자를 정의해야 하는 이유
2019. 8. 21. 01:50ㆍPL/C++
"멤버 대 멤버의 복사가 진행되는 디폴트 복사 생성자가 자동으로 삽입되니까, 굳이 복사 생성자를 직접 정의할 필요는 없지 않을까"라고 생각할 수 있다.
#include <cstring>
#include <iostream>
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];
strcpy(name, myname);
age = myage;
}
void ShowPersonInfo() const {
cout << "이름: " << name << '\n';
cout << "나이: " << age << '\n';
}
~Person() {
delete []name;
cout << "called destructor!\n";
}
};
int main(void) {
Person man1("Lee dong woo", 29);
Person man2 = man1;
man1.ShowPersonInfo();
man2.ShowPersonInfo();
return 0;
}
위 코드를 작성해서, 실행시키면 빌드 오류가 생길 것이다. 기본적으로 디폴트 복사 생성자는 '얕은 복사' 기반으로 이뤄진다. '얕은 복사'는 힙 영역에서 문제가 생긴다. 힙 영역으로 선언된 변수에 대해서 새로 생성된 객체와 기존 객체를 같이 참조하는 형태로 이뤄진다. 따라서 소멸할 때, 먼저 소멸하는 객체는 문제없이 delete를 한다. 하지만 뒤이어 소멸되는 객체는 참조하던 힙 영역의 변수가 사라졌기 때문에 빌드 오류를 발생시킨다
따라서 힙 영역의 변수를 다룰 땐 반드시 복사 생성자를 재정의해야 한다. 어려운 코드를 넣는 것이 아니라 말 그대로 변수를 하나하나 복사하는 코드를 작성하면 된다
#include <cstring>
#include <iostream>
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];
strcpy(name, myname);
age = myage;
}
Person(const Person &rhs) {
name = new char[strlen(rhs.name) + 1];
strcpy(name, rhs.name);
age = rhs.age;
}
void ShowPersonInfo() const {
cout << "이름: " << name << '\n';
cout << "나이: " << age << '\n';
}
~Person() {
delete []name;
cout << "called destructor!\n";
}
};
int main(void) {
Person man1("Lee dong woo", 29);
Person man2 = man1;
man1.ShowPersonInfo();
man2.ShowPersonInfo();
return 0;
}
[출처] 윤성우, 열혈강의 C++ 프로그래밍
'PL > C++' 카테고리의 다른 글
const 키워드 (0) | 2019.08.21 |
---|---|
임시객체 (0) | 2019.08.21 |
디폴트 생성자가 사라지는 경우 (0) | 2019.08.21 |
복사생성자와 치환연산자를 정의할 때 주의할 점 (0) | 2019.08.20 |
네임스페이스 (0) | 2019.08.20 |