[Effective C++] #11 중복 참조와 자기 대입 연산자

2022. 1. 12. 23:33· 언어/Effective C++
목차
  1. [Effective C++] #11 중복 참조와 자기 대입 연산자

[Effective C++] #11 중복 참조와 자기 대입 연산자

 

Scott Meyers의 "Effective C++"를 통해, C++ 구현에 필요한 개념들을 이해하고, 기록하기 위함입니다. 해당 항목은 2장 "생성자, 소멸자 및 대입 연산자", 항목 11 "operator=에서는 자기 대입에 대한 처리가 빠지지 않도록 하자"에 해당하는 내용입니다.

 

 


 

중복 참조에 의한 자기 대입 연산
class Wclass {...};

Wclass w;
...
w = w;

*px = *py;	// 서로 같은 객체를 가리킬 수도 ...

a[i] = a[j]; 	// 같은 값일 수도...

보통 자기 대입 연산은 적법한 코드로 분류됩니다. 쉽게 말해, 사용자 쪽에서 문제가 발생한지 모를 수 있죠. 위 예제 코드는 일단 보기에 크게 문제 될 건 없어 보입니다. 하지만 밑에 있는 예제 코드를 살펴보죠

 

A& A::operator=(const A& 우변_객체){
    delete pA;			// 클래스 A를 가리키는 포인터의 비트 할당을 해제합니다.
    pA = new A(*우변_객체.pA);	// 우변 객체의 포인터를 좌변 객체의 포인터가 가리키도록 합니다.
    return *this;
}

대입 연산을 적용한 두 객체가 만약 같은 객체라면, 위 코드는 큰 문제가 될 수 있습니다. "delete"연산은 A를 가리키는 포인터 객체의 비트 할당을 해제합니다. 이때, 좌변의 객체와 우변의 객체가 같다면, 두 객체 모두 자원이 해제됨과 동시에 텅 비어있는 객체 간의 무의미한 대입 연산이 발생하겠죠. 따라서, 우리는 중복 참조자에 대한 자기 대입 연산을 방지하기 위해 여러 가지 방법들이 필요하겠죠. 아래에서 살펴보겠습니다. 

 

1. 일치성 검사
A& A::operator=(const A& 우변_객체){
    if(this == &우변_객체) return *this;	// 일치성 검사
    
    delete pA;			// 클래스 A를 가리키는 포인터의 비트 할당을 해제합니다.
    pA = new A(*우변_객체.pA);	// 우변 객체의 포인터를 좌변 객체의 포인터가 가리키도록 합니다.
    return *this;
}

간단한 방법부터 보겠습니다. 대입 연산 내부의 시작을 일치성 검사로 시작하는 방법입니다. 우변의 객체와 좌변의 객체가 같다면, 좌변의 객체를 반환하고 끝냅니다. 하지만, 또 다른 위협이 도사리고 있죠. 바로 "new A"를 통해 동적할당하는 부분에서 예외가 발생하면 pA는 텅 빈 포인터를 갖고 홀로 남게 되겠죠. 여기서 우리는 예외에도 안전한 소스코드로 수정해 보려 합니다. 

 

A& A::operator=(const A& 우변_객체){
    
    A *pB = pA;		// 먼저 pA 가 가리키는 객체를 pB에 임시로 저장해 놓습니다.
    
    pA = new A(*우변_객체.pA);	
    delete pB;		//동적 할당이 성공적으로 끝나면, 임시 객체를 해제합니다.	
    
    return *this;
}

위 예제 코드는 임시 포인터를 만들어 좌변 객체를 가리키는 포인터를 별도로 저장해 놓고, 동적 할당을 진행합니다. 따라서, 예외로 부터 안전한 대입 연산 진행이 가능해집니다! 

 

2. swap
class A {
public:
    ...
    void swap (A& 우변_객체);
	...
};

A& A::operator=(const A& 우변_객체){
    A temp(우변_객체);	// 임시의 A 객체에 우변 객체를 복사 생성자를 통해 복사합니다.
    
    swap(temp);
    
    return *this;
}

두 번째 방법은 "swap"연산을 사용하는 방법입니다. 우변 객체의 복사본을 임시로 생성해 좌변 객체와 swap 연산을 실행합니다. 결과적으로 좌변 객체는 우변 객체의 값을 전달 받고 반환됩니다. 사본을 만드는 방법들을 살펴봤습니다. 우리가 이미 알고 있는 내용으로 "값에 의한 전달"을 수행하는 함수는 해당 객체의 사본을 만든다는 것도 알고 있죠! 값에 의한 전달로 대입 연산자를 작성해도 도움이 됩니다!

 

중복 참조자에대한 자기 대입 연산을 방지하기 위해 대입 연산자 본문에 일치성 검사, 혹은 사본이나 복사를 통해 텅 빈 객체를 가리키거나, 예외로 부터 안전할 수 있습니다.

 

'언어 > Effective C++' 카테고리의 다른 글

[Effective C++] #14 자원 관리 객체 심화, RAII, shared_ptr, 삭제자 지정  (0) 2022.01.14
[Effective C++] #13 자원 관리 객체, std::auto_ptr, std::shared_ptr  (0) 2022.01.14
[Effective C++] #10 대입 연산자와 *this의 참조자  (0) 2022.01.12
[Effective C++] #9 가상 함수를 호출하는 생성자, 소멸자  (0) 2022.01.10
[Effective C++] #8 소멸자가 던지는 예외  (0) 2022.01.10
  1. [Effective C++] #11 중복 참조와 자기 대입 연산자
'언어/Effective C++' 카테고리의 다른 글
  • [Effective C++] #14 자원 관리 객체 심화, RAII, shared_ptr, 삭제자 지정
  • [Effective C++] #13 자원 관리 객체, std::auto_ptr, std::shared_ptr
  • [Effective C++] #10 대입 연산자와 *this의 참조자
  • [Effective C++] #9 가상 함수를 호출하는 생성자, 소멸자
Hardii2
Hardii2
Hardii2
개발 블로그
Hardii2
전체
오늘
어제
  • 분류 전체보기
    • 알고리즘
    • 웹 개발
      • Node.js
      • React
    • 게임개발
      • DirectX12
      • 관련 지식
      • Unreal C++
      • Unreal 블루프린트
    • 언어
      • Effective C++
      • Basic C++
      • 디자인 패턴
      • 자료구조
      • 기술 질문
    • 문제 풀이
      • BOJ 문제 풀이
      • Programmers 문제 풀이
      • geeksForgeeks 문제 풀이
    • 수학
      • 확률과 통계
      • 게임수학
    • 개인프로젝트
    • 그룹프로젝트
      • PM
      • Dev
    • Github

블로그 메뉴

  • 홈
  • 글쓰기

공지사항

인기 글

태그

  • stl
  • unreal
  • Unreal Blueprint
  • 알고리즘
  • 기술 질문
  • Effective C++
  • 개발
  • BOJ
  • 정렬
  • BFS
  • 우선순위 큐
  • programmers
  • 그래프
  • 트리
  • C++
  • set
  • dfs
  • 디자인 패턴
  • DP
  • 최단 경로

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.2
Hardii2
[Effective C++] #11 중복 참조와 자기 대입 연산자
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.