비공개2011. 7. 7. 16:27

항목 1. C++를 언어들의 연합체로 바라보는 안목은 필수

C++ 이란?   상관 관계가 있는 여러 언어들의 연합체( federation)
                     C++를 구성하는 요소들은 각각의 규칙을 가지고 있다. 

■ C++ 구성요소

1) C 

2) 객체 지향 개념의 C++ : 클래스, 캡슐화, 상속, 다형성, 가상 함수( 동적 바인딩 ) 등

3) 템플릿 C++ : 새로운 프로그래밍 패러다임 파생 -> 템플릿 메타프로그래밍( TMP )

4) STL
템플릿 라이브러리( 컨테이너 / 반복자 / 알고리즘 / 함수 객체 ... )



 

 

항목 2. #define을 쓰려거든 cosnt, enum, inline을 떠올리자

            부제 : 가급적 선행처리자( define )보다 컴파일러를 더 가까이 하자
 

■ define 키워드 단점

1) define 관련 컴파일 에러시 에러메세지 내용이 직관적이지 못하다.  
 

1
2
3
4
5
6
/*
다음 define 관련하여 컴파일 오류가 생길 경우
에러 메세지에서 'MAX_COUNT' 어쩌구는 거론되지않고 
'100'이라는 숫자만 거론됨. ;;;
*/
#define MAX_COUNT 100
   

■ define을 상수( const )로 교체하라 

1) 부동소수점을 쓸 경우에는 define을 썻을 때보다 최종코드의 크기가 작아 질 수 있다.

2) 기호 테이블에 들어가며 컴파일 문제 발생시 정확한 위치를 직관적으로 표시해준다.


■ define -> const 변경시 유의점

1) 상수 포인터를 정의하는 경우    
 

1
2
3
4
5
6
7
8
9
/*
포인터와 가르키는 대상까지 const로 선언해주자.
*/
const char * const authorName = "Scott Meyers";

/*
char* 가 싫다면 string으로 대체
*/
const std::string authorName("SocttMeyers");
 


2) 클래스 맴버로 상수를 정의하는 경우


1
2
3
4
5
6
7
8
9
10
// .h file
class CostEstimate
{
private :
	static const double FudgeFactor;
	
};

// .cpp file
const double CostEstimate::FudgeFactor = 1.35;

 
■ 클래스 내에서 상수가 필요할때는 enum 이 최고!

1) const보다 #define에 가깝다. int 자료형으로 취급되며 상수값만 유효하다.

2) 메모리에 할당 되지 않는다.

3) 클래스내에서의 enum은 다양한 설계에 유용하게 활용된다.
    템플릿 메타프로그래밍의 핵심 기법이기도 하다.

■ 함수처럼 쓰이는 매크로로 만들고자 한다면 #define 매크로 보다 inline 함수를 우선 생각하자.

  1) #define 매크로 잘못 사용 한 예

1
2
3
4
5
6
7
#define CALL_WITH_MAX(a,b) ( (a)>(b) ? (a):(b) ) // 매크로 전체를 ()로 감싸지 않으면 책임못짐;;

int a = 5;
int b = 0;

CALL_WITH_MAX( ++a, b );     // a는 2번 증가! 뭥미;;;
CALL_WITH_MAX( ++a, b+10 ); // a는 1번 증가! 
 

2) inline 함수 템플릿

1
2
3
4
5
template< typename T >
inline int callwithMax( const T& a, const T& b )
{
	return ( a > b ? a : b );
}
 





 

항목 3. 낌새만 보이면 const를 들이대 보자!

■ const 의미 해석법

const가 *표의 왼쪽    : 포인터가 가르키는 대상이 상수
const가 *표의 오른쪽 : 포인터 자체가 상수


■ const의 효과 예시
 

1
2
3
Temp a, b, c;

if( a * b = c ) // 으악… 나는 비교( a * b == c ) 하려 했었는데… ㅠㅠ


const Temp Operate* ( const Temp& rhs ); 처럼
const 를 사용하면 위와 같은 실수를 미연에 방지하여 error 메시지를 발생시킨다.

 



 

항목 4. 객체를 사용하기 전에 반드시 그 객체를 초기화하자


■ 대입과 초기화를 헷갈리지 말자

 

1
2
3
4
5
6
7
8
9
10
// [대입] 기본 생성자 호출 -> 대입 연산자 호출!
Test::Test( const std::string& name, 
			const std::string& address, 
			const std::list<PhoneNumber>& phones )
{
	theName		= name;
	theAddress	= address;
	thePhones	= phones;
	nCount		= 0;
}

- 맴버 초기화 리스트를 사용 한 것보다 비용이 큼

- C++ 규칙에에 의하면 어떤 객체이든 그 객체의 데이터 맴버는
   생성자의 본문이 실행되기 전에 초기화 되어야 한다고 명기 되어있다.
   이방법을 '초기화'라고 생각하지 말자.


 
1
2
3
4
5
6
7
8
9
10
11
// [초기화] 복사 생성자 한번 호출
Test::Test( const std::string& name, 
			const std::string& address, 
			const std::list<PhoneNumber>& phones )
	: theName(name),
	  theAddress(address),
	  thePhones(phones),
	  nCount(0)
{
	/* Nothing */
}


- 자신의 코딩 정책으로 '맴버 초기화 리스트'를 적용하자. ( 습관화 / 의무화 )

- 만약에 나열된 초기화할 객체가 많아 길어지는게 마음에 걸린다면 ???
   
대입으로도 초기화가 가능한 데이터 맴버들을 빼내어 별도의 함수( ex. init() )로 옮기는 것도 방법이다.


초기화 순서

 

1) 기본 클래스는 파생 클래스보다 먼저 초기화 된다.

2) 클래스 데이터 맴버는 그들이 선언된 순서대로 초기화된다.

 

가급적 선언된 파라메타 순서 그대로 초기화 해주는 습관을 기르자
 

 

정적 객체 ( static object )


extern / static 키워드를 사용하여 선언한 객체!!
 

- 종류

1) 전역 객체

2) 네임스페이스 유효범위에서 정의된 객체

3) 클래스 안에서 static으로 선언된 객체

4) 함수 안에서 static으로 선언된 객체( 지역 전역 객체 )

5) 유효범위에서 static으로 선언된 객체

 

 

- 문제가 발생 할 수 있는 부분

별개의 번역 단위에서 정의된 비지역 정적 객체들의 초기화 순서는 정해져 있지 않다

 

- 해결책( Singleton pattern )

함수를 두어 최초 호출시 객체를 생성하고 그 이후로는 참조자만 반환해주자. 

1
2
3
4
5
6
7
class FileSystem { ... };

FilesSystem& tfs()
{
	static FileSystem fs;
	return fs;
}
 

비지역 정적 객체 -> 지역 정적 객체로 교채!!! 
   
Posted by 닭꽝