| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 |
| 23 | 24 | 25 | 26 | 27 | 28 | 29 |
| 30 |
- NRVO
- RootMotion
- GeeksForGeeks
- 언리얼엔진5
- 줄 세우기
- UnrealEngine4
- Unreal Engine5
- 오블완
- algorithm
- Effective C++
- softeer
- UnrealEngine5
- C++
- 1563
- 티스토리챌린지
- directx
- 프로그래머스
- DirectX11
- UE5
- 백준
- RVO
- IFileDialog
- winapi
- 팰린드롬 만들기
- C
- Programmers
- const
- TObjectPtr
- baekjoon
- 2294
- Today
- Total
Game Develop
operator= (대입연산자) 에서 자기대입에 대한 처리가 빠지지 않도록 하자. 본문
여기서 말하는 자기대입(self assignment)란, 어떤 객체가 자기 자신에 대해 대입연산자를 적용하는 것을 의미한다.
대충 아래처럼?
Widget w;
w = w;
이게 왜 위험한가... 아래의 예시코드를 먼저 보자.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class Bitmap {};
class Widget
{
public:
Widget& operator= (const Widget& rhs)
{
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
private:
Bitmap* pb;
};
|
cs |
위의 예시코드는 안전하지 않은 대입연산자 코드이다.
왜? rhs가 자기자신일 수 있으니까. 맨 처음의 w = w를 생각해면 된다.
그러면 Bitmap 포인터변수가 같은 놈이라는건데, 대입연산자 첫줄에 delete pb를 해버린게 보이는가?
그러면 rhs의 pb도 delete 됐다는 것이다.
그 상태에서 rhs의 pb를 이용해서 메모리할당을 시도하니 문제가 생길 수 밖에 없다.
이런 현상을 막기위한 제일 쉬운 방법은 자신과 rhs를 비교해서, 다를때만 대입연산자를 시도하는 것.
if (this == &rhs) return *this; // 이 코드 한줄만 앞에 추가해주면 된다.
|
1
2
3
4
5
6
7
8
9
10
11
12
|
Widget& operator= (const Widget& rhs)
{
if (this == &rhs)
{
return *this;
}
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
|
cs |
이런식으로.
근데 이 코드도 안전하지 않은 부분이 있다.
new Bitmap부분에서 예외가 발생해버리는 경우다. (뭐 동적할당 메모리가 부족하다던지, *rhs.pb를 이용한 Bitmap의 복사생성 자체에서 예외가 터져버린다던지...)
예외가 발생해버리면 그냥 pb만 delete해버린 꼴이다. 이런 객체가 남겨져 있으면 어떤 예상치 못한 상황이 발생할 지 알 수가 없다.
댕글링 포인터가 된 셈.
그러니 예외가 발생할 경우를 대비해, 무작정 삭제한다음에 새로 할당하려하지 말고 혹시 모르니 기존값을 미리 저장 후, 새로 할당받고 기존값을 삭제하는 흐름으로 진행하면 안전하다.
|
1
2
3
4
5
6
7
8
|
Widget& operator= (const Widget& rhs)
{
Bitmap* pOrig = pb;
pb = new Bitmap(*rhs.pb);
delete pOrig;
return *this;
}
|
cs |
이런식으로...
보면 기존값을 pOrig라는 새로운 지역변수에 미리 저장한다음 동적메모리할당을 시도한다.
예외가 발생하더라도 pb는 기존값을 유지하고 있기 때문에 이전의 방법보다 더 안전하다.
그리고 if문으로 자기자신인지 검사할 필요도 없다. 원본 pb로 새로 할당받고, 기존꺼는 지역변수에 보관한다음 그걸 delete 하니까.
'C++ > Effective C++' 카테고리의 다른 글
| 객체 생성 및 소멸과정중에는 절대로 가상함수를 호출하면 안된다. (0) | 2025.11.12 |
|---|---|
| 불필요한 복사생성자, 복사대입연산자 호출을 미리 막아보자. (0) | 2025.03.01 |
| 객체를 사용하기 전에 반드시 그 객체를 초기화하자. (0) | 2025.02.18 |