3. Item 1: 짬뽕언어 C++
• 다중 패러다임 프로그래밍 언어
• 절차적 (procedure),
• 객체지향 (object-oriented),
• 함수형 (functional),
• 일반화 (generic),
• 메타프로그래밍 (meta-programming)
4. Item 1: 짬뽕언어 C++
• 다중 패러다임 프로그래밍 언어
• 절차적 (procedure) C언어 기반으로 제작
• 객체지향 (object-oriented) 클래스를 쓰는 C
• 함수형 (functional) 람다
• 일반화 (generic) 템플릿, STL
• 메타프로그래밍 (meta-programming) TMP
5. Item 1: 짬뽕언어 C++
• 여러 하위 언어들의 연합 (FEDERATION)
• Divide And Conquer
• 단 하나의 정답은 없다.
7. Item 2 : #define 쓰기 전에 잠깐만..
• #define 정의의 문제점
• #define ASPECT_RATIO 1.653 //OUT
• 전처리기에 의해 단순 전치되는 값.
• 컴파일 기호 테이블에 들어가지 않는다.
• 컴파일 디버그에서 의미파악 불분명
• 사용할 때마다 사본 생성 (ex: 긴 문자열의 경우)
8. Item 2 : #define 쓰기 전에 잠깐만..
• 일반 상수 변수를 사용하자
• const double AspectRatio = 1.653;
• 컴파일러가 인식하는 기호
• 사본 생성 X
• const char* const authorName = “Scott Meyers”;
• 상수 포인터는 내용 상수성 체크
• 문자열 상수는 왠만하면 std::string 씁시다.
9. Item 2 : #define 쓰기 전에 잠깐만..
• 클래스 멤버 상수면 static 쓰자.
• 상수의 scope를 클래스로 제한할 때
• 헤더에만 쓰면 정의 아니고 선언
• 주소가 필요한 경우 cpp에 정의 필요
• const int GamePlayer::NumTurns;
• 상수 초기화는 선언에 하는 것이 옳다
class GamePlayer
{
...
private:
static const int NumTurns = 5;
...
};
10. Item 2 : #define 쓰기 전에 잠깐만..
• 정적 멤버 상수 못쓰는 경우
• 컴파일러 구린건 정적 멤버 선언 시 초기화 못함.
• 초기값을 상수 정의 시점에 주면 된다.
• 클래스 컴파일 시점에 클래스 전용 상수가 필요하다면?
• Enum Hack! (나열자 둔갑술…이름 구림)
• enum { NumTurns = 5};
• 마치 scope가 있는 #define마냥 사용할 수 있다.
• TMP에서 자주 사용되는 기법.
11. Item 2 : #define 쓰기 전에 잠깐만..
• 눈물이 나려고 하는 #define 매크로 함수
• #define MAX(a, b) f((a) >(b)) ? (a) : (b)
• 인자로 뭐가 들어갈지 알 수가 없다.
• inline 템플릿 함수로 바꿔 쓰자.
• inline으로 매크로의 효율을 유지하면서 안전하게 사용가능
int a = 5, b = 0;
MAX(++a, b); //a == 7
MAX(++a, b + 10); //a == 6
template<typename T>
inline void max(const T& a, const T& b)
{ return (a > b) ? a : b; }
13. Item 3: 일단 const를 쓰고 생각한다.
• const의 멋짐을 모르는 당신은 너무 불쌍해
• 의미적 제약을 소스 코드 수준에서 붙일 수 있음
• const == “외부 변경 불가능”
• 이 제약을 컴파일러에서 처리함.
• 빠른 오류 검출
• 전역 상수 정의 할 때도 사용됨 (item 2)
14. Item 3: 일단 const를 쓰고 생각한다.
• 복잡한(것 처럼 보이는) 규칙
• const(데이터의 상수성) char * const (포인터의 상수성)
• STL iterator의 상수성
• 반복자는 T *와 동작원리가 같다.
• const로 반복자를 선언하면 가리키는 대상을 보존한다.
• 데이터의 상수성은 const_iterator를 사용하여 보존할 수 있다.
15. Item 3: 일단 const를 쓰고 생각한다.
• 함수에서 const (1)
• 반환값이 const
• 불필요한 에러를 줄일 수 있다.
• “훌륭한 클래스는 쓸데없는 비 호환성을 피한다.“
class Rational
{
const Rational operator*( const Rational& lhs, const Rational& rhs );
};
Rational a, b, c;
...
If(( a * b ) = c){ … } //컴파일 에러
16. Item 3: 일단 const를 쓰고 생각한다.
• 함수에서 const (2)
• 상수 멤버 함수
• 상수 객체에서도 호출 가능한 함수
• 멤버 변수들의 값을 바꾸지 않음.
• 함수의 상수성을 표현하는데 유익한 인터페이스
• 자주 쓰이는 const T&가 사용할 수 있는 함수
17. Item 3: 일단 const를 쓰고 생각한다.
• 함수에서 const (3)
• 일반 멤버 함수에 상수 멤버 함수를 오버로딩한다.
• 상수 객체, 비 상수 객체 모두 상황에 따라 사용할 수 있도록.
• ex) T의 배열 객체에서 operator[]
• 비상수 멤버 함수 : const T& 리턴
• 상수 멤버 함수 : T& 리턴 ( 왜 T&인지는 알겠지? )
18. Item 3: 일단 const를 쓰고 생각한다.
• 함수에서 const (3-1)
• 오버로딩에서 코딩 중복을 피하는 방법
• 리턴 형식 빼고 거의 똑같은 코드라면?
• 상수버전 함수를 호출하고 const_cast를 사용한다.
• 비 상수 버전을 상수버전에서 호출하면 안된다.
• 상수 멤버 함수의 상수성이 보존될 거라고 장담할 수 없음.
char& operator[](std::size_t position)
{
return const_cast<char&>
( static_cast<const TextBlock&> ( *this )[position] );
}
19. Item 3: 일단 const를 쓰고 생각한다.
• 함수에서 const(4)
• 상수 멤버 함수의 물리적 상수성
• 객체를 구성하는 비트 값 변경 불가능 멤버변수에 대입연산 불가능
• 포인터 멤버 변수의 주소만 일치하면 OK 내용 변경 가능
• 불완전한 상수성
20. Item 3: 일단 const를 쓰고 생각한다.
• 함수에서 const(5)
• 상수 멤버 함수의 논리적 상수성
• 물리적 상수성을 보완하기 위해서 만든 개념
• 몇 개의 변수를 활용하여 직접 상수성 체크
• 상수성 검증에 필요한 변수들 변경가능해야함
• 이때 사용되는 것이 mutable
• 어떤 상황에도 변경할 수 있는 변수임을 선언하는 키워드
size_t TextBlock::length() const
{
if(!lengthIsValid) {
textLength = strlen(pText);
lengthIsValid = true;
}
return textLength;
}
22. Item 4: 잊지 말자 초기화
• C( in C++ )의 자동 초기화를 믿지 말자
• 상황에 따라 초기화 할 때 있고 안 할 때 있음
• C( in C++ )의 초기화 규칙은 복잡 다난
• 초기화 되지 않은 값은 undefine behavior의 어머니
• 그러니까 항상 직접 초기화를 하자
• 일반 변수는 직접 손으로 초기화
• 클래스의 멤버변수들은 하나도 빠짐없이 생성자에서 초기화
23. Item 4: 잊지 말자 초기화
• 대입 vs 초기화
• 생성한 뒤에 값을 집어 넣으면 대입
• 생성할 때 값을 지정하면 초기화
• C++ 초기화 규칙
• “객체의 멤버는 생성자 본문이 실행되기 전에 초기화 되어야 한다.”
• 생성자 호출 한 번 vs 생성자 + 대입연산 두 번.
• 초기화 리스트 쓰세요
24. Item 4: 잊지 말자 초기화
• 초기화 리스트
• 초기화 리스트의 인자는 멤버 변수의 생성자의 인자로 처리
• 인자가 없으면 기본 생성자 호출
• 상수 혹은 참조자 타입 멤버는 필수적으로 초기화 필요.
• 선언하는 헤더에서 초기화가 안된다면, 초기화 리스트로!
25. Item 4: 잊지 말자 초기화
• Class 멤버들의 초기화 순서
1. 부모 클래스가 자식 클래스보다 먼저 초기화 된다.
2. 클래스 멤버변수는 선언 순서로 초기화 된다.
• 초기화 리스트에서 순서를 달리해도 초기화 되는 순서는 같다.
• 빠른 오류 검출을 위해서 초기화 리스트 순서와 선언 순서를 맞춰준다.
3. 비지역 정적 객체의 초기화 순서는 개별 번역 단위에서 정해진다.
• ???
26. Item 4: 잊지 말자 초기화
• 비 지역 정적 객체의 초기화 순서 문제 (해설편)
• 비 지역 정적 객체
• 전역 객체, 네임스페이스 안의 전역 객체, 클래스의 정적 멤버 객체, 파일 유효범
위에 선언된 static 객체
• 번역 단위
• 전처리(#include) 까지 마친 목적파일의 단위
• 별개의 번역 단위에 있는 비 지역 전역 객체의 경우
• 한쪽이 초기화 되어도 다른 한쪽이 초기화 되었다고 보장할 수 없다.
27. Item 4: 잊지 말자 초기화
• 비 지역 정적 객체의 초기화 순서 문제 (해답편)
• 비 지역 정적 객체가 문제라면 지역 정적 객체를 쓴다.
• 함수를 사용해서 정적 객체의 참조자를 리턴 받아 사용.
• 맨날 쓰는 Singletone 패턴
• 지역 정적 객체는 반드시 초기화 된 상태의 객체를 쓰도록 설계한다.
• 안 필요하면 안 만들게 설계한다.
28. Item 4: 잊지 말자 초기화
• 쓰레드 프로그래밍에서 정적 객체 초기화는?
• 어디서 어떻게 초기화될지 아무도 모른다.
• 다중 쓰레드 돌입하기 전에 한번씩 GetInstance() 호출
• 객체 초기화 순서는 꼬이지 않게 알아서 잘 짜야한다.
• A 초기화 B가 필요 B 초기화 A가 필요 (노답)
• 이렇게 되어버리면 앞에서 말한 건 다 무 쓸모