일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Multithread
- sequential
- Unreal
- Design Pattern
- vector
- 쓰레드
- 디자인패턴
- 옵저버
- observer pattern
- 유니크포인터
- MultiCore
- 한국산업기술대학교
- 게임공학과
- 옵저버 패턴
- 멀티코어
- EFFECTIVE C++
- 복사생성자
- 스마트포인터
- thread
- c++
- 프레임워크
- 메모리관리
- random access
- 멀티코어 프로그래밍
- material
- multi-core
- 멀티쓰레드
- stl
- Atomic
- C
- 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 |