[이것이 C++이다] Part 02. 객체지향 프로그래밍 (2)
Chapter 04. 복사 생성자와 임시 객체
- C++ 에서 메모리 관리 기법을 익힙니다.
- 복사 생성자
- Shallow Copy vs Deep Copy
- 임시 객체
- 이동 시맨틱
4.1 복사 생성자
- 복사 생성자는 객체의 복사본을 생성할 때 자동으로 호출됩니다.
- 클래스를 작성할 때 복사 생성자를 생략하면 디폴트 생성자처럼 컴파일러가 알아서 만들어 줍니다.
- 하지만 복사 생성자를 작성하지 않을 경우, 성능상 문제가 될 수도 있습니다.
- 복사 생성자 문법
CMyData(const CMyData& rhs);
4.2.1 복사 생성자 호출 시점
-
명시적으로 객체의 복사본을 생성할 경우
CMyData a; CMyData b(a);
-
클래스가 함수의 매개 변수로 사용되는 경우
CMyData a; TestFunc(a);
- 함수의 매개변수 형식이 클래스 형식이라면 무조건 상수형 참조로 선언 해야 합니다.
void TestFunc(const CMyData& param);
- 함수의 매개변수 형식이 클래스 형식이라면 무조건 상수형 참조로 선언 해야 합니다.
-
클래스가 함수의 반환 형식으로 사용되는 경우 (이름 없는 임시 객체와 연관이 깊다.)
CMyData a; a = TestFunc();
4.1.2 깊은 복사와 얕은 복사
- 깊은 복사 : 복사에 의해 실제로 두 개의 값이 생성되는 것.
- 얕은 복사 : 하나의 대상에 대해 접근 포인터만 늘어난 것.
-
얕은 복사의 문제점 ?
int main() { int *pA, *pB; pA = new int; *pA = 10; pB = new int; pB = pA; // shallow copy delete pA; delete pB; // 이미 해제된 메모리를 한 번 더 해제하려고 한다. return 0; }
-
어떻게 하면 될까 ?
*pB = *pA; // 두 포인터가 각각 다른 대상을 가리키게 된다.
- 디폴트 복사 생성자의 문제점
- 컴파일러가 자동으로 생성해 주는 디폴트 복사 생성자는 얕은 복사를 수행한다.
-
올바른 복사 생성자 예제
// 복사 생성자 CMyData(const CMyData& rhs) { // 메모리를 할당한다. m_pnData = new int; // 포인터가 가리키는 위치에 값을 복사한다. *m_pnData = *rhs.m_pnData; } // 소멸자 ~CMyData() { // 객체가 소멸하면 동적 할당한 메모리를 해제한다. delete m_pnData; } // 포인터 멤버변수 private: int *m_pnData = nullptr;
4.1.3 대입 연산자
- 단순 대입 (a = b;)을 시도하면 기본적으로 얕은 복사가 수행된다.
-
올바른 대입 연산자 예제
// 대입 연산자 오버로딩 CMyData& operator=(const CMyData& rhs) { *m_pnData = *rhs.m_pnData; return *this; } private: int *m_pnData = nullptr;
4.2 묵시적 변환
4.2.1 변환 생성자
- 변환 생성자의 함정
- 불필요한 임시 객체를 만들어 내 프로그램의 효율을 갉아먹는다.
class CTestData { public: // 매개변수가 하나 뿐인 생성자는 형 번환이 가능하다. CTestData(int nParam) : m_nData (nParam) { } private: int m_nData; }; void TestFunc(CTestData param) { } int main() { // int 자료형에서 CTestData 형식으로 묵시적 변환 TestFunc(5); return 0; }
- explicit 예약어를 변환 생성자 앞에 붙여서 묵시적 변환을 막을 수 있습니다.
4.2.2 허용되는 변환
4.3 임시 객체와 이동 시멘틱
- 이름 없는 임시 객체는 함수의 반환 형식이 클래스인 경우 발생합니다.
4.3.1 이름 없는 임시 객체
4.3.2 r-value 참조
4.3.3 이동 시맨틱
Chapter 05. 연산자 다중 정의
- 연산자 함수에 대해 이해합니다. 연산자 함수는 오버로딩이 가능하여 기존에 사용하던 연산자보다 더 확장성 있는 코드를 생산할 수 있습니다.
- 연산자 함수
- 연산자 다중 정의 (오버 로딩)