얕은 복사와 깊은 복사
얕은 복사는 컴파일러가 메모리 영역을 그대로 다른 객체의 메모리로 복사하는 식으로 작동합니다.
컴파일러는 클래스가 뭐하는지 뭘 가지고 있는지 관심도 없고 알지도 못합니다.
그저 클래스의 크기가 얼마인지 만 알고 있습니다.
정리하자면 어떤 크기의 메모리 영역을 복사하면 얕은 복사입니다.
2022.07.28 - [C++ 프로그래밍/클래스] - 객체의 복사와 복사 생성자
객체의 복사와 복사 생성자
같은 자료형의 변수들을 복사하는 것과 같이 객체도 서로 복사할 수 있습니다. 바로 대입연산자(=)와 복사생성자 두 가지의 이유로 복사할 수 있습니다. 대입연산자 이용 Point p(2,3), q; q = p; 복사
onesside-world.tistory.com
이 글에서 소개한 디폴트 대입 연산자와 디폴트 복사 생성자가 이러한 방법으로 동작합니다.
대부분의 클래스는 대부분 무조건적인(어떤 크기의 메모리 영역을 복사) 방법으로 복사해도 전혀 문제가 없습니다.
하지만, 클래스가 동적으로 할당된 메모리 공간을 가리키면 문제가 생깁니다.
왜냐하면, 만약 객체 A와 B가 있고 A가 arr라는 공간을 동적할당을 했고 A가 B에 얕은 복사를 하면 B도 A가 동적할당했던 arr 공간을 같이 가리키게 됩니다.
여기까지도 크게 문제가 없을 것 같습니다.
그런데, 이 상태에서 호출된 함수가 종료되어 복사된 객체 B가 소멸되면 동적할당했던 arr 공간을 메모리 해제하게 되고
후에 객체 A가 소멸되면동적할당했던 arr 공간이 없다고 버그가 뜹니다.
그렇다면 이것을 해결할려면 2가지의 방법이 있습니다
- 소심한 해결 방법
- 근복적인 해결 방법
소심한 해결 방법
가장 간단하고 가장 추천하는 방법은 대입 연산자나 복사 생성자가 호출되지 않도록 하는 것입니다.
먼저 매개변수 전달에 따른 복사 생성자를 생각해 보면 참조자는 객체가 아니라 기존 객체의 별명이므로 새로 객체를 만들지 않고, 따라서 복사 생성자도 호출되지 않습니다.
예: void add(Vector& a, Vector& b)
근복적인 해결 방법
깊은 복사는 실제 객체의 동적 할당된 공간을 가리키게 하는게 아닌 복사된 객체가 똑같은 동적할당 공간을 같도록 처리하는 것입니다.
이것이 근복적인 해결 방법입니다.
#include <iostream>
using namespace std;
class Vector {
int dim; // 벡터의 차원
double* arr; // 벡터의 각 차원 데이터
public:
Vector(int d = 0) : dim(d) { arr = new double[dim]; }
~Vector() { delete[] arr; }
void setRand(int max = 100) {
for (int i = 0; i<dim; i++)
arr[i] = rand() % (max * 10) / 10.0;
}
void print(char *str = "Vector") {
cout << str << "[" << dim << "] = < ";
for (int i = 0; i < dim; i++)
cout << arr[i] << " ";
cout << ">\n";
}
//전달되는 객체의 차원만큼 메모리를 동적으로 할당,
//할당된 메모리의 내용도 모두 복사
//이와 같은 객체의 복사를 "깊은 복사"라고 합니다.
void clone(Vector& a) {
if (dim > 0) delete[] arr;
dim = a.dim;
arr = new double[dim];
for (int i = 0; i < dim; i++)
arr[i] = a.arr[i];
}
void add(Vector a, Vector b) {
for (int i = 0; i < dim; i++)
arr[i] = a.arr[i] + b.arr[i];
}
void operator = (Vector& a) { clone(a); }
Vector(Vector& a) : dim(0) { clone(a); }
};
void main()
{
Vector u(3), v, w(3);
u.setRand();
v = u;
w.add(u, v);
u.print(" U ");
v.print(" V ");
w.print("U+V");
}
더 자세한 내용은 게임으로 배우는 C++책을 읽는걸 추천합니다. 그림도 있어서 이해하기 편합니다.
블로그의 대부분의 글은 제가 이해한 책을 3번 정독하고 깨달은 내용을 바탕으로 적고 있습니다.
코드에서 이해안되는 부분은 질문해주시면 답변하겠습니다