| 일 | 월 | 화 | 수 | 목 | 금 | 토 | 
|---|---|---|---|---|---|---|
| 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 | 
- thread
 - 쓰레드
 - C
 - EFFECTIVE C++
 - material
 - MultiCore
 - 유니크포인터
 - sequential
 - 멀티쓰레드
 - Atomic
 - 옵저버
 - 옵저버 패턴
 - Design Pattern
 - 멀티코어
 - 메모리관리
 - multi-core
 - c++
 - Unreal
 - 디자인패턴
 - 게임공학과
 - 스마트포인터
 - 복사생성자
 - 한국산업기술대학교
 - random access
 - observer pattern
 - Multithread
 - 프레임워크
 - vector
 - 멀티코어 프로그래밍
 - stl
 
- Today
 
- Total
 
태크놀로지
[Effective C++] 왜 const를 사용해야하는가 본문
1. define 대신 const, enum, inline을 사용하자
왜? 
#define ASPECT_RATIO 1.653 의 경우 
우리는 ASPECT_RATIO로 알지만, 컴파일러에게 넘어가기전 숫자 상수로 밀어버리게 됨 
에러메시지에 ASPECT_RATIO가 아닌 1.653으로 나타남
따라서 
매크로 대신 const 상수를 사용하자! 
상수를 사용할 경우 기호 테이블에 들어감. 디버깅시 확인가능 
부동소수점 실수 타입일 경우, 컴파일을 거친 최종 코드 크기가 더 작게 나올 수 있음 
-> 코드에서 ASPECT_RATIO를 사용한 코드마다 1.653으로 변경하는 사본이 생기기 때문
2. 클래스 내에 static 멤버
// header
class GamePlayer{
private:
	static const int NumTurns;	// 상수 선언 (정의 X 가능)
}
// cpp
//const int GamePlayer::NumTurns = 5;
int main()
{
	// cout << GamePlayer::NumTurns << endl; 
  	// 주석 O : 오류없음 static 메모리 접근이 없기때문에 메모리할당이 없음
    	// 주석 X : compile error : static 초기화 필요
}
주소를 취하지 않는 한, 정의 없이 선언만 해도 아무 문제가 없게 되어있음. 
이 때 클래스 상수의 정의는 cpp파일에 두어야한다. h에 놓을경우 클래스 상수의 초기값은 해당 상수가 선언된 시점에서 바로 초기화됨
(1~2) 정리
- 단순한 상수를 사용할때는, #define보다 const객체 혹은 enum을 우선 생각하자. 
- #define 매크로 함수는 좋지않다. 인라인(template) 함수를 우선으로 만들자
3. const 위치에 따른 정의
const char* p : 객체가 const / 포인터는 non-const
(char const* p와 동일)
char* const p : 포인터가 const / 객체는 non-const 
(즉 객체를 가리키고 있는 포인터를 변경할 수 없다.)
const char* const p : 둘다 const 
[예제]
int main() {
	vector<int> vec;
	const vector<int>::iterator iter = vec.begin();
	// 반복자가 const 따라서 반복자를 변경하지 못함
	*iter = 10; 
	// ++iter; 에러
	vector<int>::const_iterator cIter = vec.begin();
	
	// 객체의 상수성을 갖고있음 따라서 반복자 변경가능하지만, 객체 변경 불가능
	// *cIter = 10; 에러
	++cIter;
}
4. 상수 멤버 함수
예시) 
const X operator*()일경우 
if (a*b = c) 컴파일러에서 이러한 오타방지 가능 (==인데 =만 쓴경우) 
const X operator[] () 일경우 : X의 값이 const 
X operator[] () const 일경우 : 함수 자체가 const (operator 함수내에 값변경이 일어나지 않음.)
5. 논리적 상수성
const 객체로 생성했지만, 값이 변경되어 버리는 상황이 발생
class CTextBlock {
public:
	CTextBlock(char* str) {
		pText = str;
	}
	~CTextBlock() = default;
	// &가 없을시 컴파일오류 : 원본이 아님
	// const
	/* const */ char& operator[](size_t position) const {
		return pText[position];
	}
	// non-const
	char& operator[](size_t position) {
		return pText[position];
	}
private:
	char* pText;
};
int main()
{
	char a[6] = "Hello";
	const CTextBlock ctb(a);
	ctb[0] = 'x';
	// 논리적 상수성
	// 비트수준 상수성에서 알지못함.
	// 비트수준 상수성: 구성하는 비트중 어떤것도 바꾸면 안됨
	// 객체가 const지만 값이 바뀌어버림
	cout << ctb[0] << endl;
}
-> 상수형과 비상수형 operator함수를 제작하자.
6. const멤버함수 및 non-const 멤버함수내에서 중복현상 피하기
mutable을 사용시 const함수내에서 쓰기가 가능 
상수멤버함수와 비상수멤버함수에서 같은 검사 코드가 발생했을시, 중복코드를 없애보자.
class CTextBlock {
public:
	CTextBlock(char* str) {
		pText = str;
	}
	~CTextBlock() = default;
	// &가 없을시 컴파일오류 : 원본이 아님
	// const
	const char& operator[](size_t position) const {
		// 경계검사
		// 접근 데이터 로깅
		// 자료 무결성 검증
		if (!lengthIsValid) {
			textlength = strlen(pText);
			lengthIsValid = true;
		}
		return pText[position];
	}
	// non-const : 중복코드 제거
	char& operator[](size_t position) {
		
		return
			// const 떼어내기
			const_cast<char&>(
				// const로 형변환 후
				// const 연산자 실행
				static_cast<const CTextBlock&>
				(*this)[position]
				);
	}
private:
	char* pText;
	mutable size_t textlength;
	mutable bool lengthIsValid;
};
-> 비상수멤버함수에서 상수멤버함수를 호출
(3~6) 정리
- const를 붙여 선언하면 컴파일러가 에러를 잡는데 도움을 줌. 안전성
- 논리적 상수성을 사용해서 프로그래밍 해야함 
- 상수멤버 및 비상수 멤버함수가 기능적으로 서로 똑같을 경우, 코드중복을 피하기 위해 비상수함수가 상수함수를 호출하도록 만들어라.
출처

'C++' 카테고리의 다른 글
| [Effective C++] 생성자와 소멸자, 제대로 메모리 관리를 하고 있는가? (0) | 2020.11.19 | 
|---|---|
| [Effective C++] 객체 생성시 초기화 방법 (0) | 2020.11.18 | 
| [C++/STL] Ranking System 분석 (0) | 2020.09.25 | 
| [C++/STL] Ranking System 소개 및 구현 (0) | 2020.09.25 | 
| [C++] vector 메모리 관리 구조 분석 (0) | 2020.08.07 |