본문 바로가기
프로그래밍/More Effective C++

항목7. &&, ||, 혹은 , 연산자는 오버로딩 대상이 절대로 아니다.

by 리뷰하는 (게임)프로그래머_리프TV 2011. 6. 30.


시작은 단축 평가 처리에 대해서 언급되어 있다.

복합적인 불린 표현식을 평가 할 때.
모든 조건을 다 보는것이 아니라. 특정 조건으로 인해 최종 결과 값이, 참 또는 거짓 이라고 판명이 났을 때.
남은 조건들을 검사하지 않고 넘어 가는 것을 말하는데.

	char* p;

	if( ( p != 0 ) && ( strlen(p) > 10 ) ) ...
	// 이 경우 p != 0 임이 확인 되면 strlen은 확인하지 않는다.
	// && 연산자 임으로 둘중 하나만 거짓이면 어차피 거짓이니까.

	if( ( index < lowerBound ) || ( index > upperBound ) ) ...
	// 이 경우도 마찬가지다.
	// 만약 index가 lowerBound 보다 작다면,
	// upperBound 와의 연산은 구지 하지 않는다.
	// || 연산자 임으로, 어차피 참이면 뒤 값이 뭐가 됐던 참이니까.​


여기 까지는 이미 알고 있거나, "아 그렇군!" 하고 넘어 가면 그만인데
이제 &&, || 연산자를 오버로딩 한다고 생각하자.

다음과 같은 문제가 발생한다.

	// && 연산자를 오버로딩 했다는 전재로...
	if( ex1 && ex2 )
	// 이 부분이 컴파일러에게는
	if( ex1.operator&&(ex2) )
	// operator&&가 멤버 함수 일 경우
	if( operator&&(ex1, ex2) )
	// operator&&가 전역 함수일 경우​


다음 처럼 보여진다는 것이다.
잘 이해가 가지 않을 수도 있지만.
쉽게 생각하면 문제는 다음과 같다.
첫째, 모두 검사를 해야 하기 때문에 단축 평가가 이루어 지지 않는다.
둘째, ex1이 먼저 평가 될지, ex2가 먼저 평가 될지 모른다는것이다.
단축 평가는 c, c++에서 정해져 있는 기본 기능이다.
만약 &&, || 연산자를 오버로딩 하지 않았다는 전재로.
단축 평가를 생각하면서 조건식을 넣었던 A씨는
B씨의 오버로딩으로 문제가 발생할 여지가 존재한다는 것이다.
물론 그런 부분을 처음에 약속하여 방지 하는 것은 가능할지도 모르겠으나.
그것이 옳지 않은 방법이라는 것은 구지 말하지 않아도 충분히 알 것이라고 생각한다.

다음은 ,(쉼표) 연산자 인데.
사실 흔히 사용하는 연산자는 아니다.
사용하는 좋은 예를 코드로 보여주고 있는데.
내용은 다음과 같다.

void reverse( char s[] )
{
	for( int i=0, j=strlen(s)-1; 
		i < j; 
		++i, --j )
	{
		int c = s[i];
		s[i] = s[j];
		s[j] = c;
	}
}
​


문자열을 반전시키는 함수인데,
마지막 부분을 보면 ++i, --j 를 볼 수 있다.
, 연산자의 경우 순서를 따지면
먼저 i를 증가 시키고,
그 다음 j를 증가 시킨다.
그 순서에 의문이 생긴다면,

	int i=1;
	int j=2;
	int n = (++i, --j);

	std::cout << n << std::endl;​

처럼 해보자.
값은 --j가 나올 것이다.
여튼, 이것 또한 문제만 콕 찝어서 넘어 가자면,
오버로딩 하였을 때, 그 안에서 --j를 먼저 실행할지, ++i를 먼저 실행할지
순서를 보장 할 수 없다는것!!
그렇기 때문에 , 연산자 또한 오버로딩을 하지 말아라! 라는것이 이번 항목의 결론인것 같다.

한가지 의문은 오버로딩을 할 순있지만, 해서 좋지 않을 것이라면,
애초에 하지 못하게 하는것이 더 낫지 않았을까? 하는 생각도 들긴 한다만...

뭐... 높으신 분들께서 생각이 있으셨겠죠;;하하 미천한 저 따위가 뭘 알겠나요.

이번 항목은 생각보다 별거 없었다.
앞으로 남은 모든 항목이 이런 수준의 난이도라면 참 좋겠어.제길.