자신과 동일한 타입 한 개를 인자로 가지는 생성자.
사용자가 복사생성자를 만들지 않으면 컴파일러가 디폴트 복사생성자를 제공한다.
모든 멤버를 복사한다.
디폴트의 경우는 안의 내용없이 모든 멤버를 복사한다.
class Point
{
public:
int x;
int y;
Point() : x(0), y(0) {}
Point(int a, int b) : x(a), y(b) {}
// 사용자가 만드는 복사 생성자
Point( const Point& p) : x(p.y), y(p.x)
{
std::cout << "copy ctor" << std::endl;
}
};
복사생성자가 호출되는 3가지 경우
1. 자신과 동일한 타입의 객체로 초기화 될 때
2. 함수 인자를 call by value로 받을 경우
.- 함수인자를 const reference로 사용하면 복사본을 만들지 않으므로 복사생성자가 호출되지 않는다.
3. 함수가 객체를 값으로 반환 할 때
- 참조리턴을 하게되면 복사생성자가 호출되지 않는다. (리턴값이 Point&)
+) 지역변수는 참조로 반환하면 안된다
디폴트 복사 생성자 문제점
디폴트 복사 생성자는 모든 멤버를 복사해주고 이 점이 문제가 될 수 있다.
클래스안에 포인트 멤버가 있으면 디폴트 복사 생성자가 주소만 복사되기 때문에 자원해제시 문제가 된다.
얕은복사
- 클래스 안에 포인터 멤버가 있을 때 디폴트 복사 생성자가 메모리 자체를 복사하지 않고 주소만 복사하는 현상
- 개발자가 직접 복사 생성자를 만들어야한다.
객체의 복사방법: 깊은 복사
class Person
{
char* name;
int age;
public:
Person(const Person& p) : age(p.age)
{
// 포인터는 복사 하지말고. 새롭게 메모리 할당
name = new char[strlen(p.name) + 1];
strcpy(name, p.name);
}
};
하지만 큰 크기의 깊은 복사를 많이 하게되면 메모리 낭비가 될 수 있다.
객체의 복사 방법: 참조계수(reference counting)
여러객체가 하나의 자원을 공유 하게 한다. 단 몇명의 객체가 자원을 사용하는지 개수를 관리한다.
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 = 1;
}
~Person()
{
// 참조 계수 기반인 경우의 소멸자.
if ( --(*ref) == 0 )
{
delete[] name;
delete ref;
}
}
Person(const Person& p)
: name(p.name), age(p.age), ref(p.ref)
{
++(*ref);
}
};
공유하는 객체 중 하나가 자원을 바뀌게 되는 코드가 등장하게되면 공유했던 자원은 분리되어야하고 추가코드가 들어가게된다.
멀티 스레드 환경에서는 동기화의 오버헤드가 추가된다.
객체의 복사 방법: 복사금지
class Person
{
...
Person(const Person&) = delete;
};
객체를 복사하지 못하게 하자는 의도. 복사 생성자를 delete 한다.
객체의 복사 방법: 문자열이 필요하면 STL의 string클래스를 사용
#include <string>
class Person
{
std::string name;
int age;
public:
Person(std::string n, int a) : name(n), age(a)
{
}
};
동적메모리 할당을 할 필요가 없다.
string이 내부적으로 자원을 관리해주고, int변수처럼 사용이 가능하다.
'프로그래밍 > C++' 카테고리의 다른 글
[C++] 상수 멤버 함수 const member function (0) | 2021.08.20 |
---|---|
[C++] static member 정적 멤버 데이터, 함수 (0) | 2021.08.19 |
[C++] 포인터와 레퍼런스 (0) | 2021.08.18 |
[C++] range for, if init, switch init (0) | 2021.07.25 |
[C++] 람다표현식 (0) | 2021.07.25 |