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