핵심 개념
1. 복사 생성자: 객체의 복사본을 생성할 때 호출되는 생성자
2. 깊은 복사: 실제 값을 두 개로 만드는 복사
3. 얇은 복사: 값은 하나이나 포인터만 두 개를 생성
4. 임시 객체: 컴파일러가 임의로 생성했다가 바로 소멸시키는 객체
성능 향상을 위해 이를 다루려면 ‘식별자’를 부여해야 함
5. 이동 시맨틱: 복사 생성자와 대입 연산자에 r-value 참조를 조합해서 새로운 생성 및 대입의 경우를 만든 것.
학습 목표
1. 객체를 복사할 때 어떠한 방법을 사용하는 가
2. 실제 값을 복사해서 다루는 방법 두가지
3. 보이지 않는 객체 제어
4. 새로운 문법: 이동 시맨틱
함수의 매개변수를 클래스 형식으로 선언할 때 고려할 점
1. 매개변수로 반드시 참조자를 이용한다.
2. 묵시적 변환 생성자를 지원하는 클래스인지 확인을 한다.
1. 복사 생성자: 객체의 복사본을 생성할 때 호출되는 생성자
문법: 클래스이름(const 클래스이름 %rhs);
A. 함수 호출과 복사 생성자
- 함수 형태로 호출 할 때
- 클래스가 매개변수로 사용되는 경우(함수가 클래스를 매개변수로 가질 때)
- 반환 형식으로 사용되는 경우(함수 반환 형식이 객체일 때)
l 이름 없는 임시 객체를 만들 수 있음
1) 클래스가 매개변수로 사용되는 경우를 확인
l Void TestFunc(CTestData param)으로 선언을 하게 되면,
i. 함수에서 인스턴스를 선언하게 된다. -> 메모리 낭비
ii. 복사 생성자를 삭제 -> Void TestFunc(CTestData param) = delete
l 위를 방지하여 참조자를 이용한다.
i. Void TestFunc(CTestData ¶m)
ii. 함수에서 새 인스턴스를 선언하는 것이 아니므로 효율이 좋음
iii. 클래스를 매개변수로 받기 위해선 꼭 참조자를 이용할 것
iv. 값의 변형 방지를 위해 변경해야 할 이유가 없다면 const로 참조
B. 깊은 복사와 얇은 복사
- 깊은 복사: 실제 값을 두 개로 만드는 복사
- 얇은 복사: 값은 하나이나 포인터만 두 개를 생성
i. 얇은 복사로 인해 같은 메모리 주소를 가리킬 때
l 복사본과 원본 모두 메모리 해제를 하게 되면 에러 발생
l 원본이 가리키는 메모리가 해제되고, 복사본은 댕글링 포인터가 됨
ii. 따라서, 특수상황이 아닐 경우 깊은 복사를 사용
l 복사 생성자를 생성한다.
l 메모리 주소를 복사하는 것이 아닌 데이터를 복사
C. 대입 연산자
- 단순 대입 연산자가 클래스에서도 사용 가능
l 하지만, 복사 생성자를 따로 선언하고 깊은 복사를 한 두 객체에서 대입 연산자를 사용하면 에러 발생: 기본적으로 얇은 복사가 되므로 에러
l 연산자 다중 정의로 해결 5장 내용
Ø 클래스이름& operator연산자기호(const 클래스이름& 변수이름)
2. 묵시적 변환
A. 변환 생성자: 매개변수가 한 개인 생성자
- 문제점
n 불필요한 임시 객체를 만듦
n 프로그램 효율 하향
i. 함수의 매개변수가 클래스일 때
u 함수 호출 시 int로 매개변수를 전달할 경우
l 함수 호출을 Func(클래스(int))형태로 전달됨.
u 이유: 클래스가 변환 생성자를 제공함으로써 위와 같이 컴파일
u 컴파일러가 알아서 임시 객체를 생성하고 함수로 전달한다.
ii. 위 클래스가 묵시적 변환 생성자를 지원하는지 확인 필요
u 묵시적 변환 생성자가 사용자 모르게 호출될 가능성 차단
l explicit 예약어로 차단한다.
l explicit 클래스이름(매개변수){}
B. 허용되는 변환
- 위와 같이 변환생성자를 제공한다면
n int 자료형에서 class 자료형으로 변환 가능
n class 자료형에서 int 자료형으로 변환 불가능
i. 형 변환 연산자(형변환자)
l 형식 1: operator int(void) {return m_nData};
l 형식 2: (int)클래스객체 //비추: C스타일의 강제 형 변환
l 형식 3: static_cast<int>(a)//C++스타일
ii. 형 변환 연산자에도 explicit 예약어 사용 가능
3. 임시 객체와 이동 시맨틱
- 함수 반환 형식이 클래스인 경우 발생
A. 이름 없는 임시 객체: 존재하는 인스턴스, 하지만 ‘식별자’가 부여되지 않은 객체
- 함수 반환 값이 클래스
n 클래스 객체 = 함수를 할 경우
l 함수에서 반환하는 객체가 안보이지만 생성됨을 알 수 있다.
l 함수 반환 후 객체는 소멸한다.
l ‘이름 없는 임시 객체의 원본은 임시 객체의 복사 생성이 끝난 후 소멸’
n cout << 함수.멤버함수; 일 경우
l 임시 객체 생성 후 메서드 종료 후 소멸
- 임시 객체의 참조자
n 참조자로 임시 객체를 선언하게 될 경우
l 임시 객체는 소멸하지 않고 보존된다.
l 이름은 없으나 별명은 존재
B. r-value 참조
- r-value: 단순 대입 연산자의 오른쪽 항
- 형식: int&& 이름 = 초기값;
매개변수 형식 |
실인수 예 |
|
TestFunc(int) |
Int x = 3; TestFunc(x); TestFunc(3); TestFunc(3 + 4); |
|
TestFunc(int&) |
Int x = 3; TestFunc(x); |
|
TestFunc(int&&) |
Int x = 3; TestFunc(x); TestFunc(3); TestFunc(3 + 4); |
TestFunc(x)는 불가능 |
- 다중 정의로 가능하나, 모호성 발생 가능성이 있다.
C. 이동 시맨틱: 복사생성자와 대입 연산자에 r-value 참조를 조합해서 새로운 생성
및 대입의 경우를 만들어 낸 것
- 탄생 원인: 이름없는 임시 객체
- 형식: CTestData(CTestData &&)
- 복사 생성자가 호출될 때( b = Func(20))
n r-value를 복사하려 할 때 그 임시 객체를 참조자로 매개변수를 받아 그 주소를 복사할 주소에 저장
n 어차피 사라질 객체이므로 얕은 복사를 통해 두 객체가 같은 주소를 가리키고, 임시 객체는 소멸, 복사한 객체는 보존된다.
연습문제
1. 함수의 매개변수가 클래스라면 참조자로 받는다.
2. CMyString 클래스
3. 묵시적 변환 생성자가 생성되었고 임시 객체가 생성되었다. 그로 인해 원치 않는 메모리 낭비가 된다.
explicit 예약어로 사전 차단한다.
4. 이름 없는 임시 객체의 복사 생성자
'C++ > 이것이 C++이다.' 카테고리의 다른 글
Ch7. 상속 심화 (0) | 2021.01.15 |
---|---|
Ch6. 상속 기본 (0) | 2021.01.15 |
Ch5. 연산자 다중정의 (0) | 2021.01.15 |
Ch3. 클래스 (0) | 2021.01.15 |
Ch2. C++ 함수와 네임스페이스 (0) | 2021.01.15 |
최근댓글