1. 객체의 복사 방법
#include <iostream>
#include <cstring>
class Person {
char* name;
int age;
public:
Person(const char* n, int a) : age(a) {
name = new char[strlen(n) + 1];
strcpy(name, n);
}
~Person() { delete name; }
};
int main() {
Person p1("kim", 20);
Person p2 = p1;
}
① 얕은 복사란? (Shallow Copy)
=> 클래스 안에 포인터 멤버가 있을 때 디폴트 복사 생성자가
=> 메모리 자체를 복사하지 않고 주소만 복사 하는 현상
#include <iostream>
#include <cstring>
class Person {
char* name;
int age;
public:
Person(const char* n, int a) : age(a) {
name = new char[strlen(n) + 1];
strcpy(name, n);
}
~Person() { delete name; }
Person(const Person& p) : age(p.age) {
// 포인터는 복사 하지말고, 새롭게 메모리 할당
name = new char[strlen(p.name) + 1];
strcpy(name, p.name);
}
};
int main() {
Person p1("kim", 20);
Person p2 = p1;
}
② 깊은 복사 (Deep Copy)
=> 클래스 안에 포인터 멤버가 있을 때
=> 메모리 주소를 복사 하지 말고 메모리 자체의 복사본을 만드는 기술
2. 단점 및 해결책
① 깊은 복사 (Deep Copy)의 단점
=> 객체를 여러 번 복사하면 동일한 자원(이름)이 메모리에 여러 번 놓이게 된다.
=> 자원의 크기가 큰 경우 메모리 낭비가 발생.
② 참조 계수 (reference counting)
=> 여러 객체가 하나의 자원을 공유하게 한다.
=> 단, 몇 명의 객체가 자원을 사용하는지 개수를 관리한다.
3. 참조 계수 방법
#include <iostream>
#include <cstring>
class Person {
char* name;
int age;
int* ref;
public:
Person(const char* n, int a) : age(a) {
name = new char[strlen(n) + 1];
strcpy(name, n);
// ref = new int(1); - 아래와 동일 코드
ref = new int;
*ref = 1;
}
~Person() {
// 참조 계수 기반인 경우의 소멸자
if( --(*ref) == 0 ) {
delete[] name;
delete ref;
}
}
Person(const Person& p) : name(p.name), age(p.age), ref(p.ref) {
++(*ref);
}
};
int main() {
Person p1("kim", 20);
Person p2 = p1;
}
멤버 데이터 / 생성자 / 복사 생성자 / 소멸자가 바뀌었다.
① 참조 계수 (reference counting)에서 좀 더 생각해야 할 점
=> p1 객체가 자신의 이름을 변경하면 어떻게 될까?
=> p2의 이름은 변경되면 안되므로 공유 했던 자원은 분리되어야 한다.
-> 참조 계수도 마찬가지로 분리되어야 한다.
=> 멀티 스레드 환경에서는 동기화의 오버헤드가 추가된다.
4. 이외의 복사 기법들
4.1 복사 금지
#include <iostream>
#include <cstring>
class Person {
char* name;
int age;
public:
Person(const char* n, int a) : age(a) {
name = new char[strlen(n) + 1];
strcpy(name, n);
}
~Person() { delete name; }
Person(const Person& p) = delete;
};
int main() {
Person p1("kim", 20);
Person p2 = p1; // 컴파일 에러가 나오게 하자.
}
① 복사 금지
=> 객체를 복사하지 못하게 하자는 의도
=> 복사 새성자를 delete 한다.
4.2 using STL
#include <iostream>
#include <cstring>
#include <string>
class Person {
std::string name;
int age;
public:
Person(const std::string n, int a) : name(n), age(a) {
}
};
int main() {
Person p1("kim", 20);
Person p2 = p1;
}
① 문자열이 필요하면 STL의 string클래스를 사용하자.
=> 동적 메모리 할당을 할 필요 없다.
=> string이 내부적으로 자원을 관리해준다.
=> int 변수처럼 사용하면 된다.
'프로그래밍 > C++' 카테고리의 다른 글
[C++] static member function (0) | 2019.11.17 |
---|---|
[C++] static member data (0) | 2019.11.14 |
[C++] 복사 생성자 (copy constructor) (0) | 2019.11.07 |
[C++] explicit 생성자 (0) | 2019.11.06 |
[C++] 초기화 리스트 (member initializer list) (4) | 2019.11.05 |