얕은 복사
디폴트 복사 생성자는 멤버 대 멤버의 복사를 진행한다.
이때 일어나는 복사 방식을 얕은 복사라고 한다.
이를 좀 더 자세히 설명하기 위해 아래 코드를 사용해 보겠다.
#include <iostream>
#include <cstring>
using namespace std;
class student {
private:
char* name;
int age;
public:
student(const char* myname, int myage)
{
int len = strlen(myname) + 1;
name = new char[len];
strcpy_s(name, len, myname);
age = myage;
}
~student()
{
delete []name;
cout << "called destructor!" << endl;
}
};
int main() {
student person1("Enchupin", 20);
student person2 = person1;
return 0;
}
위 코드에서 person1을 생성한 후 인자를 전달하는 과정까지는 문제가 없다.
그러나 person2 객체를 생성하고 멤버 대 멤버 복사를 진행하는 과정에서 person2.name은 person1.name을 복사한다.
그런데 이때 값을 복사하여 person2.name에 넣는 것이 아니라 주소를 복사하여 사용하는 방식으로 복사가 진행된다.
이때 일어날 수 있는 문제점은 person1.name과 person2.name이 같은 곳을 가리키고 있기 때문에
어느 한쪽의 객체의 소멸자가 호출되어 delete []name;이 실행되면 두 객체 모두 name을 사용할 수 없게 되는 것이다.
따라서 위 코드에서 "called destructor!"는 한 번만 출력되는 것을 확인할 수 있다.
*C++ 표준을 엄격히 지키는 visual studio에서는 컴파일 자체를 허용하고 있지 않다.
깊은 복사
따라서 이러한 문제를 해결하기 위해 깊은 복사를 사용해야 한다.
깊은 복사를 사용한다는 의미는 문자열의 주소값을 복사하는 것이 아닌 개별적인 값을 복사해야 한다는 의미이다.
따라서 아래 코드와 같은 복사생성자를 선언해 줌으로써 해결할 수 있다.
student(const student& copy)
:age(copy.age)
{
name = new char[strlen(copy.name) + 1];
strcpy_s(name, strlen(copy.name)+1, copy.name);
}
위 코드에서는 name을 동적으로 할당한 후 값을 복사하고 있으므로 name을 동적으로 할당한 시점에서
인자로 입력받는 객체의 name과는 다른 주소값을 가리키고 있다.
'C++ > C++ 문법' 카테고리의 다른 글
[C++] 연산자 오버로딩 (멤버함수와 전역함수에 의한 연산자 오버로딩) (0) | 2024.09.24 |
---|---|
[C++] 객체 내에서 static 변수, static 멤버함수 (0) | 2024.05.03 |
[C++] explicit (0) | 2024.04.30 |
[C++] 복사 생성자를 활용한 객체의 대입 (0) | 2024.04.29 |
[C++] this 포인터, 메서드 체이닝(Method Chaining), *this의 의미 (0) | 2024.04.29 |