반응형

BLOG main image





결론적으론 둘다 결과는 139 가 된다


반복문 횟수가 많긴 하지만 시간에 있어서 약간 차이를 보인다



        timeTest1.startTime(); 


D3DXVECTOR3 vec1(3,-7,9);


float length=0;

for (int i=0;i<10000000;++i)

{

length=sqrtf(vec1.x*vec1.x+vec1.y*vec1.y+vec1.z*vec1.z);

length=length*length;

}


timeTest1.endTime();


timeTest2.startTime();

for (int i=0;i<10000000;++i)

{

length=vec1.x*vec1.x+vec1.y*vec1.y+vec1.z*vec1.z;

}

timeTest2.endTime();







이 정도 인데 sqrt는 특히나 매프레임마다 sqrt 를 호출하는 구조라면 상수들의 제곱으로써 피할 수 있는 방법은 없는지 생각해보는 것이 좋다



p.s 다른 수학함수도 내부적으로 좀 복잡해지는 것이라면 이와 마찬가지일지만서도 sqrt 는 좀 더 그러한듯..




반응형
반응형

♥ 에러 객체란?

" 에러객체 = 에러코드 + 에러문자열 "

프로그래밍을 하다보면 종종 에러코드를 정의해서 써야하는 경우가 있다. 종종이라기보다는 항상 에러코드를 정의해야한다. C++을 사용하는 나의 경우에는 enum을 주로 이용하여 에러코드가 겹치는 것을 방지하고, 다른 언어를 사용하는 사람들도 각자의 언어에서 제공하는 여러가지 방법을 사용하여 에러 코드를 정의해 쓸 것이다. 이렇게 에러코드들을 주루룩 정의해서 쓰다보면 한가지 아쉬운 점이 꼭 생각난다. 

"에러 코드만 넣으면 무슨 에러인지 알수 있는 방법은 없을까?"

오늘 소개해볼 '에러 객체'라는 것은 위의 불편함을 조금이라도 해결해 보기 위해 만들어진 몸부림 중에 하나다.

♥ 에러 객체에게 필요한 것들?

중복은 절대 안되!!
에러 코드는 중복되어서는 안된다. 한 가지의 에러를 나타내는데 하나의 코드만 쓰여야하고, 하나의 코드는 하나의 에러만을 가리켜야한다. 그래서 사람들은 enum 같은 곳에 에러 코드들을 정의함으로써 컴파일 타임에 자동적으로 중복되는 에러 코드를 피하려한다. 우리가 필요한 에러 객체에 중복된 코드가 있는 경우엔 컴파일 타임 에러가 발생할 수 있게 해야 한다.

코드만으로 무슨 에러인지 알고 싶어요!!
MS의 에러 코드를 생각 해 보라. 당최 알 수 없는 에러 코드가 떨어진다. 그 코드가 무엇인지 알기위해서는 MSDN을 뒤져 보거나 Error Lookup 툴을 이용하여야만 한다. 물론, 범용성을 제공하기 위해서는 정수형태의 에러코드 말고 다른 형태의 뭔가를 지원한다는 것이 상당히 어렵다. 하지만 나는 내 프로젝트에서 사용할 코드들을 정의하는 것이다. 문자열이 한글이든, 영어든 한가지만 선택하면 되는 것이고, 내가 알 수 있는 내용을 써 넣으면 된다.
지금 나에게 필요한 것은 범용성 보다는 별다른 툴 없이 바로 에러 문자열을 출력할 수 있는 방법이다.

에러 코드와 에러 문자열을 한자리에서 정의 하고 싶어요!!
만일 enum으로 에러 코드를 정의하고 문자열 배열로 에러 문자열들을 정의 하는 것도 괜찮은 방법이라 생각한다. 다만 에러 정의 들이 늘어나면 늘어 날 수록 유지 보수가 힘들어진다(진짜다 직접 해봐라!! 500개가 넘는 문자열 배열 과 에러코드를 동시에 관리하면 머리에 쥐난다).

♥ 어떻게 생겼을까?
위의 요구사항을 토대로 만들어진 코드를 살펴 보자. 장황한 서두와는 달리 실상 코드는 너무나도 간단하게 만들 수 있다.

에러 객체 기본 :
enum XXX_ERRORTYPE
{
     XXX_ERRORTYPE_SUCCESS, 
     XXX_ERRORTYPE_INFO,  
     XXX_ERRORTYPE_WARN,  
     XXX_ERRORTYPE_ERROR  
};

template <int TYPE, int SERVER, int ERRNO>  
struct XXX_ERROR {
     enum {
          ErrorCode = ((TYPE << 8 * 3) | (SERVER << 8 * 2) | ERRNO)
     };
     static const char* Desc; 
};

#define XXX_MAKE_ERRORCODE(name, type, server, errno, description) \
const char* XXX_ERROR<type, server, errno>::Desc = #description; \
typedef XXX_ERROR<type, server, errno> name;

// example
XXX_MAKE_ERRORCODE(XXX_ERROR_SOMEERROR,   TZ_ERRORTYPE_ERROR, 1,  1, "XXX 에러.")

그냥 ERROR이라고 하면 다른 뭔가와 충돌이 날것 같아 앞에 XXX를 붙였다. XXX에 큰 의미를 두지는 말자.

먼저 XXX_ERROR 객체를 살펴 보자. 
ErrorCode라는 enum을 선언하고 있다. ErrorCode는 값이 아닌 하나의 타입으로 인식되어 컴파일 타임에 결정 된다. TYPE, SERVER, ERRNO 같은게 나오고 이리 저리 시프트가 있어서 복잡해 보이기는 하지만 그것은 개인적으로 에러 코드를 카테고라이징하기 위해 사용하는 것이지 특별한 의미가 있는 것은 아니다. 필요 없다면 ERRNO 하나만으로 써도 무방하다. 

Desc는 description의 약자로 static const* 타입으로 선언되어 있다. 꼴에 문자열인지라 아무래도 컴파일 타임에 뭔가를 할 수 없어 대신 런타임에 아무도 내용을 바꾸지 못하도록 const를 사용했다.

XXX_MAKE_ERRORCODE 매크로로 눈을 돌려 보자. 이 매크로는 XXX_ERROR 템플릿 클래스를 찍어내는데 사용된다. 내부에는 static 변수의 초기화와 typedef 외에 다른 일은 하지 않는다. 하지만 한가지 기억할 것이 있다. 

"템플릿 클래스는 인자가 다른 경우 다른 타입으로 여겨진다."

위에서 type, server, errno에 다른 경우 동일한 템플릿 클래스로 만들고 있지만 항상 다른 타입으로 여겨진다는 것이다. 만일 위의 세 인자가 같은 경우(혹 하나로 해도 상관은 없다)라면 동일 타입의 static 변수를 두번 초기화하려 한다고 컴파일 에러가 발생한다. 만일 name이 같은 경우 역시 typedef를 두번 하려한다고 컴파일 에러를 발생 시킨다. 어쨋든 중복된 선언을 하게 된다면 컴파일이 안되게 만들었다는 말이다.

♥ 사용은 어떻게?
에러 객체라고 하지만 실상 아무런 객체도 생성되지 않는다. 그냥 타입의 enum 상수와 static 변수에 접근하는 것 뿐이다 :

if(XXX_ERROR_SOMEERROR::ErrorCode == SomeFunction())
{
     std::cout << XXX_ERROR_SOMEERROR::Desc << std::endl;
}

위에서 사용된 SomeFunction()은 에러 객체 템플릿 클래스에 대한 어떠한 정보도 없어도 된다. 단순히 정수형태의 에러 코드를 리턴하는 것이면 된다. 리턴하는 것은 에러 객체가 아닌 에러 객체에 정의된 enum을 리턴 한다.

문자열의 출력 역시, 에러 객체에 선언된 static 변수에 접근하여 초기화된 문자열을 출력하는 간단한 형태다. 

위와 같은 방식으로 에러 정보를 관리하게 되면 에러 코드 넘버와 에러문자열을 항상 한쌍으로 관리 할 수 있으므로 관리에 용이성과, 컴파일 타임에 중복 체크를 보장 받을 수 있다.

다만 단점으로는 static 변수들의 무수한 생성과 enum 처럼 자동으로 에러 코드를 증가 시켜주는 도구가 없다는 불편함이 있다.



참조 :
 - Modern C++ Design - 안드레 알렉산드레쿠스
 - [진리는어디에] - 템플릿 특화를 이용한 튜플 클래스
 - [진리는어디에] - 템플릿 특화(Template specialize)
 - [진리는어디에] - 템플릿 특화를 이용한 멀티 키 맵(Multi Key Map)

반응형
반응형
아래 포스트한 내용처럼 pack 을 사용하기도 하지만 멤버변수 선언 순서를 잘 맞춰 선언하는 것이 효율적이다







http://pdw1208.tistory.com/entry/pragma-pack


#include <stdio.h>

struct test{
  int iNum;
  char A;
  short B;
  char C;
};

void main()
{
  struct test B;
  
  B.iNum = 1000;
  printf("구조체의 크기는 %d\n"sizeof(B));
  
}















구조체의 크기가 12라고 출력이 되었다  좀 이상하다 


int  +  char + short + char 는 즉
 4   +    1    +   2    +   1  =  8 이 나와야 정상이다 

32비트 CPU는 4바이트 최적화를 한다 다음으로는 2바이트 최적화를 한다

따라서 그림과 같이 메모리에 들어가지 않고  




아래 그림과 같이 들어간다 A다음에 3바이트가 남아서 이럴경우는 다시 2바이트 최적화를 한다 

4바이트 메모리구조에서 메모리상에서 2바이트 최적화의 경우는 앞에 2바이트 뒤에 2바이트로 최적화를 하지

위 그림에서 B와 같이 중간에 2바이트를 할당하지 않는다 아래 그림과 같이 뒤에 2바이트를 할당한다 

남은 C 즉 1바이트는 B 다음에 할당한다 그래서 구조체의 크기는 12가 나오는 것이다     

A와 B 사이의 1바이트는 죽은 공간으로 사용은 하지 않지만 메모리만 잡아먹는 죽은 공간이다 




이를 해결하는 방법이 #pragma pack 을 이용해 메모리를 1바이트 최적화를 해주는 것이다 

#include
 <stdio.h>

#pragma pack(push, 1)  // (1) 이렇게도 사용가능 
struct test{
  int iNum;
  char A;
  short B;
  char C;
};
#pragma pack(pop)  // (4)  이렇게도 사용가능 

void main()
{
  int A = 100;
  struct test B;

  B.iNum = 1000;

  printf("구조체의 크기는 %d\n"sizeof(B));
}
 



구조체 전에 

#pragma pack(push, 1) 이나 (1) 을 선언해 메모리를 1바이트 최적화를 시킨다 그렇게되

면 구조체의 크기는 선언된 변수의 자료형의 크기만큼의 구조체를 가진다 

구조체선언 다음에  #pragma pack(pop) 이나 (4) 선언해 다시 4바이트 최적화를 해준다  

32비트 CPU에서는 4바이트(32비트)의 단위로 데이터를 처리하는 것이 가장 빠르게 때문이다  즉 

#pragma pack(1) 또는 (push ,1) 이라고 선언해놓고 원래대로 돌려놓지 않는다면 속도저하의 문제가 생

길 수 있다


각변수는 메모리상에서 그림과 같이 공간을 차지한다   
 

반응형
반응형


마지막 128 전까지는 vc 어떤 버전이든 고정된 바이트를 제공한다


마지막 __m128은 부동소수 4개를 합쳐놓은 타입으로 SIMD 방식으로 벡터곱생등을 수행할 때 사용될 수 있다



std::cout<<sizeof(__int8)<<std::endl;

std::cout<<sizeof(__int16)<<std::endl;

std::cout<<sizeof(__int32)<<std::endl;

std::cout<<sizeof(__int64)<<std::endl;

std::cout<<sizeof(__m128)<<std::endl;






BLOG main image

반응형
반응형

http://sonic.tistory.com/8

class에서 다중 상속을 받게 될 경우 그 부모의 함수를 호출하는데 부모 클래스의 이름이 필요하다.

이때 해당 클래스의 이름을 적지 않아도 __super 라는 키워드를 이용해 부모클래스를 찾아 해당 

함수를 호출하도록 할 수 있다. 아래는 MSDN에 수록된 __super 의 사용 예다.

// deriv_super.cpp
// compile with: /c
struct B1 {
  void mf(int) {}
};

struct B2 {
  void mf(short) {}

  void mf(char) {}
};

struct D : B1, B2 {
  void mf(short) {
     __super::mf(1);   // Calls B1::mf(int)
     __super::mf('s');   // Calls B2::mf(char)
  }
};

반응형
반응형



http://blog.naver.com/dkfqkeorkfl/120187637909



Scott Meyers의 effective c++ 항목 30번은 inline에 관하여 이야기합니다. 

 

주제는 간단합니다.

"inline 키워드를 사용하기 위해서는 최대한 따져가며 사용해야만 한다."

 

이 주제에 대하여 자세히 읽어보면 아래와 같은 이야기를 합니다.

Scott Meyers "이야기가 나왔으니 말인데, 생성자와 소멸자는 인라인하기에 그리 좋지 않은 함수입니다"

 

생성자와 소멸자 내부를 컴파일러 어떻게 만들어내는지 알수 없을 뿐더러 혹여라도 코드의 길이에 막대한 영향을 끼칠 우려가 있기 때문입니다. 생성자와 소멸자는 자주 호출되는 함수중 하나로 암묵적인 객체까지 모두 포함되면 코드의 길이가 천문학적으로 늘어날 가능성이 존재합니다. 때문에 생성자와 소멸자에는 inline을 사용하지 말라고 권고하는 것이죠.

반응형
반응형

http://santacop.tistory.com/62




기존의 C++ enum은 다음과 같은 문제가 있었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
enum Color
{
    Red,
    Green,
    Blue,
    ...
}
 
void Foo(Color color)
{
    switch(color)
    {
    case Red: ... break;
    case Green: ... break;
    case Blue: ... break;
    }
}

enum이 전역 공간을 돌아다닐 수 있기 때문에 이름 충돌이 일어날 가능성도 높고 - 예를 들면 어디선가 const string Red = "Red"; 같은거 선언하면 모호해진다 - enum보다는 마치 #define된 상수처럼 보이며, 같은 enum소속인지도 알아보기 힘들고, 같은 enum내에 다른 멤버들이 어떤 것이 있는지 알아보기 힘들며, 어디서 사용되는지 유추할 길이 없는 등의 단점이 있다.

약간의 꼼수로는 Color_Red, Color_Green과 같은 이름을 사용하는 방법이 있긴 하다. 나도 지금까지 이렇게 해왔지만 이제 바꿀 예정!


Scoped enum을 사용하는 방법은 다음과 같다.
 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace Color
{
    enum Type
    {
        Red,
        Green,
        Blue,
        ...
    }
}
 
void Foo(Color::Type color)
{
    switch(color)
    {
    case Color::Red: ... break;
    case Color::Green: ... break;
    case Color::Blue: ... break;
    }
}
이제 각 enum형 상수들이 소속을 가지게 되었다! Visual Studio같은 IDE를 사용한다면 F12등을 누른다거나 Ctrl+Space를 눌러서 Color의 다른 멤버 목록까지 볼 수 있다.

 
다른 방법 - 밑줄 쓰기

다만 변수를 만들 때 ::Type 이라는 것을 붙여 줘야 하는데 - Color::Type 처럼 - 이것도 싫다면 Color_Red, Color_Green 등올 하는 것이 나을 것으로 보인다.

또 밑줄을 사용할 경우, 단독으로 숫자를 사용할 수 있는 장점이 있다. 예를 들면 Keys_1, Keys_2 처럼 사용하는 것도 가능한데, 만약 namespace를 사용한다면 Keys::1, Keys::2 와 같은 방법은 1과 2처럼 숫자로 시작하는 식별자는 컴파일되지 않는다는 면에서 상대적으로 장점으로 볼 수 있다. 뭐 나같은 경우 Keys::D1, Keys::D2로 쓰고 있기는 하다.

반응형
반응형

http://kyruie.tistory.com/90


Windows memory code에서 쓰이는 값들
   - 0xABABABAB : HeapAlloc으로 할당받은 메모리 바로 뒤의 가드 영역(no man's land)에 들어가는 값4
   - 0xABADCAFE : 메모리 해제중에 잘못된 포인터를 잡아내기 위해 집어넣는 초기값5
   - 0xBAADF00D : HeapAlloc이나 LMEM_FIXED flag를 준 LocalAlloc로 할당받은 메모리에 들어가는 초기값6
   - 0xFEEEFEEE : HeapFree()하고 난 뒤 해당 메모리 영역에 들어가는 값


      0xfeeefeee

반응형
반응형

http://kaludin.egloos.com/2547365




[C/VC++] 에러코드 문자열로 변환 : FormatMessage 『C/C++』


  LPVOID lpMsgBuf; 
  FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
     NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
     (LPTSTR) &lpMsgBuf, 0, NULL ); // Process any inserts in lpMsgBuf. // ... 
     // Display the string. 
  MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION ); // Free the buffer. 
  LocalFree( lpMsgBuf ); 


Windows 98 은 잘안된다고 함. 참고해주세열.

반응형
반응형

BLOG main image





추상클래스를 상속받아 인스턴스를 만들때는 자식클래스 어딘가에선 추상클래스의 모든함수=0; 을 실질적으로 자식에서 정의하는것이 좋다

빈 함수일지라도..



class objectBase_sjh{

public :

virtual ~objectBase_sjh()=0;

virtual HRESULT renderGeoMatricalNormal()=0;

};


objectBase_sjh::~objectBase_sjh()

{


}




class objectCommon_sjh : public objectBase_sjh{

protected:

typedef std::vector<TEXTUREINFO_SJH> vecTextureInfo_sjh;

objectCommon_sjh(){}


public :

};




class xFileObject_sjh : public objectCommon_sjh{

public :

public :

xFileObject_sjh(){}

~xFileObject_sjh(){}

explicit xFileObject_sjh( LPDIRECT3DDEVICE9 pD3dDevice,  

std::wstring xFileName=_T(""), 

std::wstring textureName=_T(""), 

const std::wstring& directoryPath=_T("images/")   ) }


public :

virtual HRESULT renderGeoMatricalNormal(){ return S_OK; }                                //이 함수를 지우면 에러가 발생한다, 추상클래스의 함수가 실제 정의되지 않게됨으로


};


typedef boost::shared_ptr<xFileObject_sjh> spXFile_sjh;


int main()

{

LPDIRECT3DDEVICE9 _pD3dDevice;


spXFile_sjh( 인자값 ) );


return 0;


}



반응형
반응형

http://mskyt.tistory.com/54



[1장] C++ 기본
 - explicit 생성자
 - 복사생성자 (copy constructor)
 - 복사 대입 연산자 (copy assignment operator)
 - 함수 인자로 전달될 때는 복사 생성자가 불림

항목1.  C++는 언어들의 연합체
 C + 객체지향 + 템플릿 + STL

항목2. define 대신 const, enum, inline 사용
 - 매크로 대신 상수 사용
 - 문자열일 경우 const를 앞뒤로 (상수포인터)
 - 클래스 상수 static const 사용 (구현파일에 따로 정의 필요)
 - 매크로 함수대신 inline template 함수 사용

항목3. 낌새만 보이면 const
 - const char *p : 상수 데이터
 - char *const p : 상수 포인터
 - const vector::iterator   vs  vector::const_iterator
 - 상수 멤버 함수 : 해당 객체의 논리적인 상태를 바꾸지 않겠다고 약속한 함수. const가 있고 없고에 따라 오버로딩 가능 (상수객체에 대한 함수를 따로 정의)
 - 비트수준의 상수석 vs 논리적 상수성 (사용자가 알아챌수 없으면 된다) : 논리적 상수성 파악은 힘들고, mutable 키워드로 const에서도 변수 변경 가능
 - 상수함수 비상수함수 코드 중복 - 비상수 함수가 상수 함수를 호출하도록
  const 떼어내기 :  const_cast<char&>(static_cast<const T&>(*this)[position])

항목4. 객체 초기화
 - 대입과 초기화는 다르다
 - 멤버 초기화 리스트로 복사 생성자 호출
 - 상수&참조자 변수 반드시 초기화
 - 기본클래스가 파생클래스보다 먼저 초기화됨
 - 멤버변수는 초기화 리스트 순서에 상관없이 선언된 순서로 초기화
 - 정적 객체(전역객체, 네임스페이스 전역 객체, 클래스 정적 변수, 함수내 정적 변수, 파일내 정적변수)의 초기화에 주의
     - 번역 단위 : 컴파일을 통해 하나의 오브젝트 파일을 만드는데 바탕이 되는 소스코드
     - 두개이상의 번역단위에서 비지역 정적 객체의 초기화 순서는 정해지지 않음 : 싱글턴 패턴 또는 참조자 반환 함수 사용


[2장] 생성자, 소멸자, 대입 연산자
항목5. 컴파일러 자동 생성(implicit) 함수들
 - 복사생성자, 복사대입연산자, 소멸자 자동생성
 - implicit 복사생성자는 각 멤버변수 복사생성
 - implicit 복사대입연산자도 각 멤버변수 복사대입
 - 참조자는 원래 자신이 참조하던 것과 다른 객체 참조 불가능

항목6. 컴파일러 자동생성 함수 금지시키기
 - 복사생성자, 복사대입생성자를 private로 선언
 - 프렌드 클래스도 안되게 : 선언만 하고 정의는 안함
 - 컴파일타임에 막고싶다면 uncopyable 클래스를 만듬

항목7. 다형성을 가진 기본 클래스는 소멸자를 가상 소멸자로
 - 팩토리 함수로 동적 할당된 객체를 쓰면, 지울때 기본클래스 포인터로 접근되고, 비가상소멸자이면 기본클래스 소멸자가 호출됨
 - 가상함수를 하나라도 가졌으면 가상 소멸자를 사용
 - 가상함수가 C++에선 클래스에 별도 자료구조 추가됨 : 실행중에 알기위해서 vptr(가상함수테이블 포인터), vtbl(가상함수 테이블) 
 - std::string, STL 컨테이너들은 비가상 소멸자

항목8. 예외가 소멸자를 떠나지 못하도록
 - vector가 소멸되다가 두번째 원소 소멸중 예외 : 미정의 동작
 - 방법1 : catch 하여 abort를 호출
 - 방법2 : 예외무시
 - 인터페이스를 분리. 안하더라도 리소스 관리하게 만들고 로그남기기

항목9. 객체 생성, 소멸시에는 가상 함수 호출 호출하지 않는다
 - 생성, 소멸자가 실행되는 동안에는 완전히 기본클래스로 보고 동작. 가상 함수더라도 기본 클래스 함수가 실행된다.

항목10. 대입연산자는 *this의 참조자를 반환하게 하자
 - A=B=C 처럼 대입연산자가 사슬처럼 얽히도록

항목11. 대입연산시에는 자기대입에 대한 처리가 빠지지 않도록
 - 중복참조(aliasing)
 - 일치성 검사(identity test)
 - 대개 예외에 안전하게 작성하면 자기대입에도 안전해진다
 - 복사후 맞바꾸기 기법 - reference copy 후 swap, pass by value로 받고 swap

항목12. 객체의 모든 부분을 빠짐없이 복사하자
 - 모든 멤버함수와 상속한 기본 클래스 복사를 빼먹지 말라
 - 복사 생성자와 복사 대입 연산자가 코드 중복되는 듯하지만,  대입연산자에서 복사생성자 호출 또는 그 역은 불가능

[3장] 자원관리
항목13. 자원 관리에는 객체가 그만
 - 팩토리 함수 : 클래스 객체를 동적할당하고 포인터 반환 해제는 호출한 쪽에서
 - 해제하기전 return이 되거나 예외가 발생하면 해제 안됨
 - 자원해제를 소멸자가 맡도록
 - 자원 관리 객체 : 자원 획득 즉시 초기화 (RAII-Resource Acquisition Is Initialization), 소멸자로 자원 해제
 - std::auto_ptr<T> : 스마트 포인터
     - 어떤 객체를 가리키는 auto_ptr의 개수가 여러개면 큰일 : 복사 생성자 및 대입연산자에서 피연산자를 null로 바꿔버림

 - tr1::shared_ptr : 참조카운팅방식의 스마트 포인터 (RCSP)
    - 가비지 컬렉션과 유사, 순환참조에 대한 해제는 안됨
 - 스마트포인터는 동적 배열에 적용시킬 수 없다

항목14. 자원 관리 클래스의 복사 동작
 - 힙에서 생긴 자원만 관리에 적합
 - RAII 객체의 복사정책 : 복사 금지 or 참조 카운팅 수행 or 관리 자원을 deep copy or 관리자원 소유권 이전
 - tr1::shared_ptr의 경우 삭제자 지정 가능

항목15. 자원관리클래스에서 관리되는 자원은 외부에서 접근할 수 있도록
 - tr1::shared_ptr, auto_ptr은 get함수를 명시적으로 지원
 - operator* 암시적 지원 또는 operator Handle() const 암시적 변환 함수

항목16. new와 delete시에는 사용형태를 반드시 맞춰라
 - 배열을 위해 할당받는 힘메모리엔 대개 배열원소의 개수가 저장됨
 - 객체 배열을 해제할 땐 delete[] 사용

항목17. new로 생성한 객체를 스마트포인터에 저장하는 코드는 별도의 한 문장으로
 - 인자로 넘기는 경우, 다른 인자 계산도중 예외가 발생하여 자원 누출 가능
 - 변수로 만들어 놓고 넘기자


[4장] 설계 및 선언
항목18. 인터페이스 설계는 제대로 쓰기엔 쉽게. 엉터리로 쓰기엔 어렵게
 - 사용자가 저지를 만한 실수를 염두
 - 인자용으로 struct만 만들어넣어도 타입 체크가능
 - enum이나 유효값 집합을 미리 정의
 - const를 붙여 엄하게 못쓰게함
 - 인터페이스를 일관성있게 : 배열 크기 이름 (length/size/count), property/method
 - 팩토리 함수는 애초부터 스마트포인터를 반환하도록
   - 스마트포인터 처음에는 null을 가리키게 해놓고 나중에 바꾸기
   - shared_ptr<A> ret(static_cast<A*>(0), deleter)
   - 교차 dll 문제 : new가 호출된 dll과 다른 dll에 있는 delete가 호출 되었을 때 런타임 에러 - shared_ptr에서 정한 삭제자가 특정 dll에서 불림으로써 해결
 - 부스트의 shared_ptr은 크기 두 배 동적 메모리 할당. 스레드 동기화 오버헤드

항목19. 클래스 설계는 타입 설계와 똑같이 취급
클래스 설계시
 - 생성과 소멸은 어떻게
 - 객체 초기화와 대입의 차이
 - 값에 의한 전달되는 경우의 의미 (복사생성자)
 - 클래스의 invariant 제약 조건
 - 기존클래스의 상속 계통망
 - 타입 변환의 허용 (암시적, 명시적)

항목20.  값에 의한 전달보다 상수객체 참조자에 의한 전달이 낫다
 - func(const T& a)
 - 사본이 전달되고, 생성 소멸에는 꽤나 고비용을 들어갈것
 - 복사손실 : 파생클래스 객체가 기본클래스 객체로 넘어갈때 잘림
 - 참조자는 컴파일러에선 사실상 포인터로 구현됨

항목21. 함수에서 객체를 반환해야 할 경우 참조를 반환하려 들지 말자
 - 지역변수의 참조를 넘겼다간 소멸되면서 잘못됨
 - 함수내 동적할당을 받았다면 누가 delete를?
 - 값에의한 리턴을 하더라도 대부분의 컴파일러는 생성/소멸 최소화하도록 최적화됨

항목22. 데이터 멤버가 선언될 곳은 private 영역
 - public : 일관성 사라짐. 캡슐화
 - protected : 파생클래스에게 public이랑 동일

항목23. 멤버함수보다는 비멤버 비프렌드함수와 더 가까워지자
 - 멤버함수가 적을수록 캡슐화가 잘된 것. 자유도가 높음
 - 편의 함수들을 여러파일에 쪼개서, 같은 네임스페이스

항목24. 타입변환이 모든 매개변수에 대해 적용되어야 한다면 비멤버 함수를 선언하자
 - 클래서 선언 밖에 함수 선언
 - 암시적 타입 변환에 대해 매개변수가 먹혀들려면 매개변수 리스트 있어야한다
 - 퍼블릭 함수로만 가능하다면 프렌드로 안해도 됨

항목25. 예외를 던지지 않는 swap
 - 표준 swap 구현 : 복사가  3번 일어남
 - pimpl (pointer to implementation) 기법
     - 복사비용이 높은 경우 포인터만 swap 
     - template<> 완전 템플릿 특수화 - pimpl 구현을 위한 특수화
     - template<typename T> 부분 특수화
 - 인자기반탐색(쾨니그탐색?)
 - using std::swap으로 특수화된 swap 찾고, 안되면 일반 std::swap 사용
 - 일반적인 구현 : public으로 하나 만듬. 비멤버 동일 네임스페이스에 하나 만듬. std::swap 특수화 버전만듬
 - 예외를 던지면 안됨 : 컴파일러가 강력한 예외안정성을 보장으로 도움을 주려면
 
 
[5장] 구현
항목26. 변수 정의는 늦출 수 있는 데까지 늦추자
 - 생성과 호출 비용
 - 기본생성자가 불리는 비용도

항목27. 캐스팅은 절약하자
 - 4가지 캐스팅
     - const_cast : 객체의 상수성을 없애는 용도
     - dynamic_cast : 안전한 다운캐스팅. 높은 런타임 비용
     - reinterpret_cast : 하부 수준 캐스팅
     - static_cast : 암시적 변환을 강제로 진행할 때
 - 객체 하나가 어떤 클래스로 캐스팅 되느냐에 따라 포인터 오프셋이 달라짐 - 런타임에 계산됨
 - 다중상속되면 무조건. 단일상속에서도
 - dynamic_cast : 클래스 이름 문자열 비교 기반 - 차라리 기본클래스에 가상 함수를 두도록 
 - 잘 작성된 c++ 코드는 캐스팅을 거의 쓰지 않는다

항목28. 내부에서 사용하는 객체에 대한 핸들을 반환하는 코드는 되도록 피하자
 - 참조자, 포인터, 반복자는 모두 핸들
 - private 멤버변수에 대한 접근을 허용하는 셈
 - 무효참조핸들 : 바깥으로 떨어져 나간 핸들은 그 핸들이 참조하는 객체보다 더 오래 살 위험이 있음

항목29. 예외안전성이 확보되는 그날 위해 싸우고 또 싸우자

 - 자료구조 오염 방지을 목표로
 - 3가지 보장 단계
   - 기본적인 보장 : 모든 것을 유효한 상태로 유지하겠다는 보장. 객체 내부적 일관성을 유지
   - 강력한 보장 : 예외가 발생하면 프로그램 상태를 절대로 변경하지 않겠다. 원자적인 동작 보장
   - 예외불가 보장 : 예외를 절대로 던지지 않음
 - 할 수 있다면 예외불가 보장이 좋겠지만, 현실적으론 강력한 보장 또는 기본적인 보장
 - 강력한 보장 대표적인 기법 : copy and swap, pimpl 관용구 - 객체 사본 수정후 마지막에 반영 - 전부 바꾸거나 아예 안바꾸거나
 - 함수 부수 효과 : 함수내 상태를 바꾸는 함수를 부를 때 보장성이 낮아짐

항목30. 인라인 함수는 미주알고주알 따져서 이해해두자
 - 컴파일러가 문맥별 최적화
 - 목적 코드 크기가 커짐. 페이징 회수 증가. 명령어 캐시 적중률 감소
 - inline은 요청이지 명령이 아님
 - 클래스 선언에 함수를 정의하면 인라인으로
 - 인라인 함수는 헤더파일 안에 정의해주는게 좋음 - 링크 타임이 아니라 컴파일 타임에 해줘서 (템플릿도 마찬가지)
 - 복잡한 함수나 재귀함수, 가상함수 등은 컴파일러가 인라인 무시
 - 함수 포인터로 접근하면 함수 본문 생성됨
 - 생성자와 소멸자는 인라인으로 하기 애매
 - 라이브러리 개발자 입장에선 인라인은 뻔히 보일때만.함수를 바꾸면 컴파일을 다시해야함. 인라인이 아니면 링크만 다시해도됨

항목31. 파일 사이의 컴파일 의존성을 최대로 줄이자
 - C++은 인터페이스와 구현이 그리 깔끔하게 분리돼있지 않음
 - 구현세부사항(private 멤버변수)가 헤더파일 선언부에 들어있음
 - 표준라이브러리 헤더는 어지간하면 컴파일 병목이 안됨. 특히 precompiled header를 사용한다면
 - 스몰톡이나 자바는 포인터 뒤에 구현부를 숨김
 - 마찬가지로 pimpl 기법을 사용 : 핸들클래스
 - 정의부에 대한 의존성을 선언부에 대한 의존성으로 바꾸어 놓자!
    - 객체참조자, 포인터로 할 수 있다면 객체를 직접 사용하지 말자 : 객체 크기를 알아내려면 정의부를 보는 수밖에
    - 할 수 있다면 클래스 정의 대신 클래스 선언에 최대한 의존하도록 : 함수 선언시엔 클래스 정의가 필요 없음. 전방선언 하자
 - 실제로 쓰지도 않을 타입 정의에 대해 사용자가 의존성을 끌어오지 않도록
    - 선언부와 정의부에 대해 별도의 헤더파일 제공 : 헤더파일을 짝으로 관리
 - C++에선 템플릿 선언과 정의가 분리될 수 있도록 export 키워드 제공
 
- pimpl 관용구 핸들클래스와 구현클래스 멤버함수 1대1 대응
- 핸들클래스 대신 인터페이스 클래스(가상클래스) 사용 : 포인터나 참조자로 밖에 사용 못함
- 팩토리 함수나 가상 생성자 제공


[6장] 상속 그리고 객체 지향 설계
항목32. public 상속 모형은 반드시 is-a를 따르도록
 - 파생클래스 is a 기본클래스 (일종이다)
 - 정사각형 클래스는 직사각형 클래스를 상속받기 좀 그렇다. 직사각형의 모든 성질(및 허용정도)가 정사각형에 적용 되지 않을 수 있음
 
항목33. 상속된 이름을 숨기는 일은 피하자
 - 기본클래스에서 오버 로드 했더라도 파생클래스에서 오버라이딩 했으면 가려진다 - 매개변수 타입이 다르거나 말거나
 - using을 통해 명시적으로 끌어낼수 있다.
 - private 상속을 받는다면 using도 안 통함. 전달함수 만들어야 한다.

항목34. 인터페이스 상속과 구현상속의 차이
 - 순수가상함수 : 파생클래스에서 다시 선언해야. 정의가 전혀 없음
 - 단순가상함수 : 오버라이딩 가능. 기본구현 물려받음
   - default는 있지만, 오버라이딩을 권할 때 : 순수 가상함수로 해놓고 protected로 디폴트함수 구현
   - 헤더 파일에서 인라인 호출
   - 굳이 protected 함수 만들고 싶지 않다면 순수 가상함수 구현해놓고 파생클래스에서 명시적 호출
 - 비가상 함수 : 클래스 파생에 상관없이 변하지 않는 동작
   - 필수적 구현도 물려받음. 재정의하면 안됨

 - 실수1 : 모든 함수를 비가상 함수로. 특히 소멸자는 안됨
 - 실수2 : 모든 함수를 가상함수로

항목35. 가상함수대신 쓸 수 있는 것들
 - 비가상 인터페이스 관용구를 통한 템플릿 메서드 구현
    - private으로  가상함수 선언. public 비가상 함수서 가상함수 호출
    - 비가상 함수 인터페이스 : non virtual interface / template method / 가상함수 wrapper
    - 사전/사후 동작 넣게 좋음 : 뮤텍스, 로그 등
 - 함수 포인터로 구현한 전략 패턴
    - 케릭터 생성자에 체력치 계산용함수 포인터 넘김
    - typedef int (*HealthCalcFunc)(const GameCharacter& gc)
    - 같은 클래스로 다른 계산법, 런타임에 계산법 교체
    - 비공개 데이터로 접근이 불가능. 캡슐화를 약화시켜야함
 - tr1::function으로 구현한 전략패턴
    - 함수 호출성 객체
    - typdef std::tr1::function<int (const GameCharacter&)> HealthCalcFunc
    - 템플릿으로 시그니쳐를 받음
    - 인수 및 반환값의 암시적 변환을 허용
    - 함수객체 만들기 : struct HealthCaclulator { int operator()(const GameCharacter&) const; }

항목36. 상속받은 비가상 함수를 파생 클래스에서 재정의하는 것은 절대 금물
  - 비가상함수는 정적 바인딩

항목37. 상속받은 함수의 기본 매개변수 값은 재정의 금지
  - 기본 매개변수도 정적 바인딩

항목38. has-a 혹인 is-implemented-in-terms-of를 모형화할 때는 객체 합성
  - 함성(composition) - layering containment aggregation embedding
    - 응용 영역 객체간 합성 : has-a
    - 구현 영역 객체간 합성 : is implemented in terms of
  - list 자료 구조로 set을 만든다고 해도 list를 상속받으면 안됨. list를 멤버변수로 들고있어야

항목39. private 상속은 심사숙고해서 구사하자
  - 암시적 타입 변환 안됨
  - 기본클래스로 부터 상속받은 것들이 private로
  - 구현만 물려받고 인터페이스는 물려받지 않는다.
  - 객체 합성으로 대체할 수는 있음
  - 파생클래스가 기본클래스의 비공개 부분에 접근시 or 가상함수 하나이상 재정의 할 때
  - 공백기본클래스 최적화 : unary_function, binary_function
  - is-a 관계가 아닌데 protected 멤버변수에 접근하고 플때

항목40. 다중 상속은 심사숙고 사용
  - 두 기본클래스에서 같은 이름을 사용할 경우 모호성이 생김
    - mp.BorrowableItem::checkOut() 같이 사용해야 
  - 마름모꼴 상속
    - 데이터 중복 상속을 막으려면 가상 상속을 해야함
    -  basic_ios, basic_istream, basic_ostream, basic_iostream이 마름모꼴 상속 클래스 템플릿
    - 가상상속시, 파생클래스에서 가상 기본 클래스를 초기화할 때 가상 기본클래스의 거리에 상관없이 초기화를 책임져야함
    - 웬만하면 쓰지 말고, 쓰더라도 데이터 최소화
  - 객체합성을 쓰고싶지만 가상클래스라서 데이터로 못들고 있을 때 - public으로 기본 클래스 상속. private로 객체합성용 클래스 합성


[7장] 템플릿과 일반화 프로그래밍
 타입 안정성을 위해 도입
 일반화 프로그래밍이 발전하면서 템플릿 메타프로그래밍이 탄생

항목41장. 암시적 인터페이스와 컴파일 타임 다형성
 - 객체지향 : 명시적 인터페이스 explicit interface, 런타임 다형성 runtime polymorphism
 - 템플릿 : 암시적 인터페이스implicit interface, 컴파일 타임 인터페이스 compile time interface
 - 제대로 컴파일 되기 위한 인터페이스
   - 명시적 인터페이스 : 함수시그니쳐 기반
   - 암시적 인터페이스 : 유효 표현식

항목42. typename의 두가지 의미
 - template<class T> class Widget,  template<typename T> class Widget - 완전히 똑같은 구문
 - 의존이름 : 템플릿 매개변수에 종속된 경우
    -  C::const_iterator *x : C가 뭔지 모르는 이상, const_iterator가 정적 클래스 변수로 인쇡되어 x와 곱하기 하는 구문으로 인식 될 수도
    - c++에선 중첩 의존 이름을 만나면 기본적으로 타입이 아닌것으로 간주
    - typename C::const_iterator iter 이런식으로 해야 정확
    - 중첩의존타입이름이 기본클래스 리스트에 있거나, 멤버 초기화 리스트내의 기본 클래스 식별자로 있을 땐 typename 안붙임

 - iterator 템플릿에서 일반적으로
   - typedef typename std::iterator_traits<iterT>::value_type value_type;
   - iterator가 가르키는 자료 타입을 의미

항목43. 템플릿으로 만들어진 기본 클래스 안의 이름에 접근하는 방법
 - 파생 클래스가 인스턴스화 될때까지 템플릿 매개 변수를 모르기 때문에 기본클래스의 멤버함수가 뭔지모름 :  템플릿 특수화 버전이 있을 수 있어서.
   - template<> class MsgSender<CompanyZ> {} :  MsgSender 템플릿 매개변수가 CompanyZ일때 버젼
 - 객체지향에서 템플릿으로 가면서 상속개념 사라짐
   - 기본클래스 호출시 this->
   - using MsgSender<Company>::sendClear
   - MsgSender<Company>::sendClear
   - 명시적 한정을 하면 가상함수인 경우 좋지 않다. C++의 이른 진단 때문에 생긴 현상

항목44. 매개변수에 독립적인 코드는 템플릿으로부터 분리시키자
 - 템플릿을 남용하면 바이너리를 만들때 코드 비대화
 - 사이즈같은 비타입 매개변수를 템플릿으로 쓰는 경우 크기별로 바이너리가 생성됨 - boost::scoped_array<T> 
 - 행렬같은거 사이즈를 템플릿으로 만들면 사이즈가 상수로 전파되서 최적화가 잘됨
 - vector<int>, vector<long>은 동일

항목45. 호환되는 모든 타입을 받아들이는데는 멤버 함수 템프릿을
 - 템플릿을 사용하는 스마트포인터를 만들경우, 파생클래스->기본클래스로, const 포인터로의 변환등 암시적 변환 제공 까다로움
   - 멤버함수 템플릿 사용하여 일반화 복사 생성자 사용
   - get() 메서드를 사용하여 초기화하면 암시적 변환이 가능할 때만 컴파일됨
 - tr1::shared_pointer의 경우 포인터 타입 암시적 변환은 허용하나, 명시적으로 auto_ptr등에서의 변환은 컨트롤

항목46. 타입 변환이 바람직할 경우에는 비멤버 함수를 클래스 템플릿 안에 정의
 - 템플릿 인자 추론 과정에선 암시적 타입 변환 고려 안됨
 - friend 함수로 템플릿 없이 클래스 안에 정의
 - 함수템플릿이 아니라 함수가 선언되면 암시적 형변환이 적용가능
 - 클래스안에 비멤버함수를 선언하는 유일한 방법이 프렌드

항목47. 타입에대한 정보가 필요하다면 특성정보 클래스를 사용하자
 - STL 반복자 지원연산에 의한 분류
    - 입력반복자 : 한칸씩 전진. 한번만 읽음
    - 출력반복자 : 한칸씩 전진. 한번만 씀
    - 순방향 반복자 : 한칸씩 전진. 여러번 읽고 쓸수 있음
    - 양방향 반복자 : 한칸씩 앞뒤로 set, multiset, map, multimap
    - 임의접근반복자 : 임의칸 앞뒤로, vector, deque, string
 - 템플렛을 사용하되 반복자 특성에 따라 구현을 달리하고 플때 : 특성정보 traits을 사용
 - 해당 특성정보를 템플릿 및 그 템플릿의 특수화 버전에
 - 관용적으로 특성정보는 구조체로 구현
 - 각 자료구조별로 typedef xx_iterator_Tag iterator_category; 가 공통적으로 선언됨
 - 포인터 타입의 반복자 지원을 위해 부분 템플릿특수화 사용
 - if 문을 사용할수 있지만, 작업자 worker 함수를 오버로드하여 컴파일 타임에 동작 코드가 결정되도록
 - tr1 타입관련정보를 제공하는 특성정보 클래스가 추가됨

항목48. 템플릿 메타프로그래밍
 - 기존 런타임 작업영역을 컴파일 타임영역으로
 - 부스트의 MPL
 - TMP의 루프는 재귀함수호출이 아닌 재귀식 템플릿 인스턴스화
 - return대신 enum값으로
 - 컴파일 타임에 루프코드가 생성되었다가 최적화되면서 사라짐
 - 치수단위 정확성 확인 : 거리를 시간으로 나누는 변수에 속도값 대응
 - 행렬연산의 최적화
 - 맞춤식 디자인 패턴 구현의 생성


[8장] new와 delete를 내 맘대로
- 객체 배열 할당/해제 operator new[], operator delete[]

항목49. new 처리자와 동작 원리를 제대로 이해하자
 - 표준라이브러리로 new 처리자 설치 : set_memory_handler : new에서 예외발생시키기 전에 호출
 - 클래스별로 처리자 설정
   - static std:new_handler set_new_handler(std::new_handler p) throw();  이전 처리자 리턴
   - static void* operator new(std::size_t size) throw(std::bad_alloc);
   - static std::new_handler currentHandler; 정적변수 선언
   - new operator에서 이전 처리자 정했다가 잠시 설치했다가 해제 (RAII를 사용하면 좋음)
 - 믹스인 양식의 템플릿 클래스
   - 하위클래스는 자기자신을 템플렛 변수로 (CRTP-curiously recurring template pattern). 자기자신만을 위한 템플릿 클래스를 상속받음
 - bad_alloc이 안나고 널이 나오도록
  - new (std::nothrow) Widget 
  - 생성자에서 예외가 나올수는 있음
  - new operator에 std::nothrow를 인자로 넘기는 것

항목50. new 및 delete를 언제 바꿔야 좋은 소리를 들을지 파악해두자
 - custom new, delete operator의 구현
 - 사용 목적
   - 잘못된 힙사용 탐지 : 메모리 앞뒤로 바이트 생성. 데이터 오버런/언더럼 검사
   - 효율상승 : 메모리 사용 패텅에 특화되도록
   - 통계정보수집 : 생성 소멸 통계
   - 기본메모리 관리자 공간 오버헤드를 줄이기 위해 
   - 기본할당자 바이트 정렬보장하기 위해
   - 메모리 군집화를 위해 : 해당 자료구조를 담을 힙을 별도 생성. 페이지 폴트 가능성 최소화
   - 공유 메모리상 할당 해제
 - 바이트 정렬
   - operator new 함수는 어떠한 타입에도 바이트 정렬을 만족시키는 포인터 라야
   - malloc 함수는 만족
   - 굉장히 어렵기 때문에 왠만하면 그냥 사용. 컴파일러에서 디버깅 제공하기도.
   - 메모리 관리용 상용 툴도 잇음
   - 부스트 풀Pool 라이브러리도 좋다

항목51. new 및 delete를 작성할 때 따라야할 기존의 관례를 잘알아두자
 - 메모리 할당이 가능하면 포인터 주소 리턴. 못하면 bad_alloc 예외 발생
 - 0바이트를 요구해도 1바이트 요구로 간주
 - new 처리를 호출
 - while 문으로 메모리 할당 계속 시도
 - sizeof(X) 만큼이 인자로 전달됨
 - 상속되면서 new 함수가 오버라이드 되지 않으면, 상위 클래스 것이 불림 -> 사이즈 비교해서 다르면 표준 할당자로
 - delete : 널포인터에 대해 호출할 때 안전해야

항목52. 위치지정 new 작성하면 위치지정 delete도 같이

 - 생성자에서 예외가 발생하면 메모리를 해제해줄 수가 없어서 C++ 런타임 시스템이 맡음
 - new-delete 페어를 맞춰줘야
 - 위치지정 new : 할당해줄 주소를 인자로 받음. <new> 표준 라이브리에 있음. vector에서도 사용
 - C++ 런타임 시스템이 new와 같은 시그니쳐의 delete 콜
 - 표준 형태들
    - void* operator new(std::size_t) throw(std::bad_alloc);  기본형
    - void* operator new(std::size_t, void *) throw();  위치지정
    - void* operator new(std::size_t, const std::nothrow_t&) throw();  예외불가
 - 어떤 형태든 new가 선언되면 표준형 다 가려짐
 - 표준형들 몰아놓은 기본클래스 만들고, using xxx::operator new; 로 표준형들을 사용할 수 있도록


[9장] 그 밖의 이야기
항목53. 컴파일러 경고를 지나치지 말자
 - 일단 경고를 없애는게 좋다. 최소한 경고가 의미하는 바를 정확히 알자
 - 컴파일러마다 경고가 다를 수도

항목54. TR1을 포함한 표준 라이브러리 구성 요소와 편안한 친구가 되자
 - 현재 표준 : c++98, 차기 표준 : c++0x, tr1 : Technical Report 1
 - C++98 특징
   - STL
   - iostream
   - locale, wchar_t, wstring
   - 복소수, 수치 처리
   - 예외 클래스 계통
 - TR1
   - 스마트포인터 : std::tr1::shared_ptr, weak_ptr (순환구조일때 처리)
   - tr1::function : 시그니처가 호환되는, 함수 호출성 개체(callable entity) 표현
        tr1::function <std::string (int)> func. 인자가 int로 반환값이 string으로 변환가능한 함수
   - tr1::bind 인자 바인드
   - 해시 기반 컨테이너 : unordered_..
   - 정규표현식
   - 튜플
   - tr1::array : 정적 배열 STL
   - reference_wrapper : 참조자가 객체처럼 사용되도록
   - 우수한 난수 발생기
   - 특수 용도 수학 방정식
   - 타입 특성 정보 trait : 기본제공 타입인지, 암시적 변환이 가능한지 등
   - result_of  함수 호출의 반환 타입 추론

항목55. 부스트
 - 공개 동료 심사 방식 오픈소스 라이브러리
 - 변환 : numeric_cast, lexical_cast
 - 문자열 텍스트 처리
 - 컨테이너
 - 함수객체, 고차 프로그래밍 람다함수
 - 일반화 프로그래밍
 - 템플릿 메타프로그래밍
 - 수학 및 수치 조작
 - 정확성 유지, 테스트
 - 타언어 운용 지원 (python)
 - 메모리
 - 기타 : CRC, 날짜 시간, 파일 시스템 등
 

반응형
반응형

http://blog.naver.com/wonjinho81?Redirect=Log&logNo=90162829555



순수 가상 함수가 하나도 없는 클래스를 추상 클래스로 만들고 싶을때에는 소멸자를 순수 가상 함수로 만든다.

당연한 얘기겠지만 하위 클래스의 소멸자가 호출된후 기반클래스 소멸자도 호출이 되므로

순수 가상 소멸자의 정의를 반드시 해줘야한다.

 

 

class MyClass {

  MyClass ();

  virtual ~MyClass () = 0;

};

 

MyClass::~MyClass() {}







순수 가상함수란? 추상 클래스를정의할때의 추상 클래스로부터 파생한 클래스가 무엇이건

그 함수만은 반드시 구현해야 한다는 것을 알려주는 것이라고 볼 수 있겠다..

 

 

추상 클래스를 상속받아서 파생클래스를 만들경우를 생각해보자

 

예를들어 전기제품에는 "전원을 켜다 power_on" 이라는 동작이 있을 것이다.

 

전기제품은 어디까지나 "전기를 사용하는 제품" 이라는 실체가 없는 개념적인 단어이기에

이를 추상클래스로 사용할 것이며 TV와 플레이 스테이션은 이를 상속받아 전원을 넣고 무엇을 할 것인가에 

대한 동작을 구현 하면 된다.

 

또한 추상클래스로 하려면 클래스가 가진 함수중 하나라도 순수 가상함수로써 정의하면 된다.

(추상 클래스와 인터페이스를 헷갈리는 경우가 많은데, 추상클래스는 일반 멤버, 함수, 순수가상함수등을 

모두 포함한 클래스를 말하며 인터페이스는 모두 순수가상함수로 이루어진것을 말한다)

 

class AbstractElectronics

{
    public:
        virtual void power_on() = 0;
        virtual ~AbstractElectronics();
};

AbstractElectronics::~AbstractElectronics(){}


//TV
class Television : public AbstractElectronics
{
    public:
        void power_on(){ cout << "Television Power ON !!" << endl; }
};

// 플레이 스테이션
class PlayStation : public AbstractElectronics
{
    public:
        void power_on(){ cout << "PlayStation Power ON !!" << endl; }
};

int main()
{
    // AbstractElectronics *pElectronic = new AbstractElectronics(); // 생성할수없음

    AbstractElectronics *pTV = new Television();
    AbstractElectronics *pPlayStation = new PlayStation();

    pTV->power_on();
    pPlayStation->power_on();

    delete pTV;
    delete pPlayStation;

    return EXIT_SUCCESS;
}

 

// AbstractElectronics *pElectronic = new AbstractElectronics();가 되지 않는것은

power_on(이라는 동작이 구체적으로 정의되어 있지 않기 때문이다.

 

 

 순수 가상 소멸자가 필요한 경우

 

순서가 이미 결정되어거나 기본동작이 이미 있는 것을 추상화 한다고 생각해보자

 

예를들어 칼(날붙이류)를 생각해보자.

칼은 "자르다" 라는 동작이 있다.

 

잘드는 나이프도 식칼도 투핸디드소드도 마찬가지일것이다.(이들을 통틀어 "칼"이라고 부를 뿐..)

여기서도 마찬가지로 "칼" 이란것은 개념으로 칼의 실체는 존재하지 않는다.

"칼"의 실체 자체는 식칼이나 투핸디드소드를 말한다.

 

따라서 "칼"이란 추상화한것이라고 할 수 있다

구현하면 다음과 같다.

 

class AbstractCutlery

{
    public:
        virtual void cut(){ cout << "Cut" << endl; } // 기본 동작
        virtual ~AbstractCutlery();
};

AbstractCutlery::~AbstractCutlery(){}


//구현할 것이 따로 없다
class Kitchenknife : public AbstractCutlery{};
class TwoHandedSword : public AbstractCutlery{};

int main()
{
    AbstractCutlery * pCutlery = new AbstractCutlery();        //이게 문제!!
    AbstractCutlery * pTHSword = new TwoHandedSword();
    AbstractCutlery * pKitchinKnife = new Kitchenknife();

    pCutlery->cut();
    pTHSword->cut();
    pKitchinKnife->cut();

    delete pCutlery;
    delete pTHSword;
    delete pKitchinKnife;

    return EXIT_SUCCESS;
}

 

칼의 기본동작인 자르다 cut은 추상클래스에서 의미 구체적으로 정의되어 있다.

그러나 소스코드에서와 같이 이대로는 추상클래스인 Cutlery까지 인스턴스화할수 있다.

 

순수가상함수가 없기 때문에 추상클래스로써의 기능을 하고 있지 않아서 이다.

이 동작은 원래의 의도가 아니다.

 

이럴때 순수가상소멸자를 사용한다.

순수가상함수가 존재하는것을 컴파일러에에게 알려줌으로써 이 클래스는 추상클래스로써의  역할을 하는 것이다.

 

그냥 소멸자에 평소 순수가상함수처럼 만들듯이 사용하면 된다.

 virtual ~AbstractCutlery() = 0;

 

추상 클래스를 상속한 파생클래스에서는 순수 가상함수 내부를 구현해야 하는데.

소멸자는 모든 클래스에서 반드시 정의해야 하므로( 또는 정의 되어 있으므로 (기본 소멸자)), 

추상클래스로 역할이 필요할때에 적합하다고 할 수 있다.

 

만일 전기제품에서 power_on을 순수가상함수로 정의하고선 추상 클래스에서 내부를 구현한 경우에는

파생 클래스에서 상속 받은 함수를 호출 하는 것도 가능하고

power_on 자체가 순수가상함수이기에 의 AbstractElectronics  인스턴스화를 하지 못하도록 방지하는것도 할 수 있다.

 

 class AbstractElectronics

{
    public:
        virtual void power_on() = 0;
        virtual ~AbstractElectronics();
};

AbstractElectronics::~AbstractElectronics(){} 

 

//추상클래스에서 내부를 구현
void AbstractElectronics::power_on()
{
    cout << "AbstractElectronics Power ON !!" << endl;
}



//TV
class Television : public AbstractElectronics
{
    public:
        void power_on()
        {
            AbstractElectronics::power_on();
            cout << "Television Power ON !!" << endl;
        }
};

// 플레이 스테이션
class PlayStation : public AbstractElectronics
{
    public:
        void power_on()
        {
            AbstractElectronics::power_on();
            cout << "PlayStation Power ON !!" << endl;
        }
};



int main()
{
    // AbstractElectronics *pElectronic = new AbstractElectronics(); // 생성할수없음

    AbstractElectronics *pTV = new Television();
    AbstractElectronics *pPlayStation = new PlayStation();

    pTV->power_on();
    pPlayStation->power_on();

    delete pTV;
    delete pPlayStation;

    return EXIT_SUCCESS;
}

 

 

 

 

그림이 영 없으니...

 

반응형
반응형

BLOG main image




class A{

public :

float x,y,z;

A(){

x=3;

y=5;

z=7;

}


operator float*(){

return &x;

}


 // 이부분의 주석만 제거하면 operator float*() 가 아닌 float& operator [] 으로 수행된다, 컴파일러마다 다른지는 확인 않함

/*float& operator [](int index)

{

return *((&x)+index);

}*/


};


int main()

{

A ai;

std::cout<<ai[0];            결과는 3  5  7


return 0;

}

반응형
반응형

http://blog.niu.kr/21


rand() 함수에 대해서...

전에 면접을 보고 rand() 함수에 대해 조금 자세하게 자료를 모아 봤습니다.

일반적으로 rand()함수는 random한 값을 가지게 됩니다.

하지만 그냥 rand()함수를 쓰게 되면 항상 같은 결과가 나오는걸 볼수 있는데 이건 왜 이럴까요?

이건 rand 함수가 항상 새롭게 랜덤한 수를 생성하는게 아니고 일정한 난수표를 가지고 있기 때문에 이러한 결과가 나오게 됩니다. 그래서 유사난수 생성기(pseudorandom number generator)라고 부릅니다. 그리고 이 난수표를 결정하는것이 바로 종자값이라고 부르는 seed 입니다.
그리고 이 시드값을 결정해 주는 함수가 바로 srand()인것입니다.

하지만,

 srand(1);
 printf("%i %i %i\n", rand(), rand(), rand());

같은 프로그램을 돌려보면 실행할때마다 세개의 값이 항상 같은것을 알수 있습니다.
그래서 이 시드값을 정할때는 시간을 초단위로 돌려주는 time 함수를 사용하게 됩니다.

 srand(time(NULL));
 printf("%i %i %i\n", rand(), rand(), rand());

보통 0~9까지의 랜덤한 숫자를 얻을때 rand()%10 처럼 나머지 연산자를 사용하게 되는 경우가 많은데 이경우 큰 결점이 생기게 되는데 이는 나머지 연산자가 상위비트들을 잘라내므로 기존 rand 함수가 생성하는 수의 패턴인 20억보다 훨씬 짧은 주기의 수치들이 나오게 됩니다. 반복되는 패턴이 더 적은 효과적인 난수 생성기를 만들기 위해서는 발생된 수의 하위비트들이 아닌 상위비트들을 사용해야 하는데 이를 위해서는 나누기를 이용합니다.

 rand() % 10; 
 rand() / (RAND_MAX/10.0f);

둘다 같은 0~9까지의 숫자를 가져오지만 실제로는 그렇지 않다. rand 함수는 0~RAND_MAX의 값을 가져오게 되는데 VC6에서 RAND_MAX의 값은 0x7FFF이기 때문에 골고루 분포된 값을 가지기 힘들다. 이를 테스트해보기 위해서 0~999의 숫자를 생성하는 함수를 10000000번 호출하는 프로그램을 만들어 해당 분포도를 체크하였다.

사용자 삽입 이미지

결과에서 알수 있는것은 0x7FFF 즉 0~32767의 숫자를 생성하기때문에 이를 1000으로 나머지 연산을 하게 되면 나머지가 0~767인 숫자는 33번, 768~999인 숫자는 32번이 된다. 그렇다면 평균적으로 나머지가 0~767인 숫자는 10000000/32768*33=10070번, 768~999인 것은 10000000/32768*32=9765번이 나오게 되며 위와같은 그래프가 나오게 되는 것이다. 즉, 비교적 안정된 난수를 얻고 싶으면 나누기 연산을 사용하자( ..)a

추가적으로 rand() 보다 표준편차가 더 적은 난수 알고리즘이 있으니 바로 Mersenne Twister, MT19937라고도 하고 MT알고리즘이라고도 부르는 메르센 트위스터입니다. 소스는 http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html 에서 받을수 있고, init_genrand(seed)로 시드를 결정(=srand), genrand_int32()로(=rand) 32비트의 정수를 생성할수 있습니다.

하지만 이 난수를 발생하는 알고리즘들은 표준편차가 적은 일직선의 그래프가 나옵니다. 그렇다면 난수가 정규분포를 가지게 하려면 어떻게 해야 할까요?

이전 면접때 이 질문에서 턱 막히더군요-_-) 대답은 간단합니다.
난수를 더하면 됩니다;;
가령 0~1000의 정규분포를 가지는 가지게 하고 싶다라면 0~100까지의 난수를 10번 생성해서 더하면 됩니다.
아마 검색해보면 일반적으로 -1~1까지의 정규분포를 가지게 만드는 것을 찾을수 있을겁니다.

소스보기

less..

forinti=0 ; i<1000 ; i++ )
{
    cout << val = randND( 70.0f ) << endl;
}


floatrandND( floatcenter )
{
/*
X_i = (0,1)

     sum(X_i) - n/2
Z = ----------------
       sqrt(n/12)

if n=12,
then Z=sum(X_i) - 6

*/
   
floatsum=0.0f;
    forinti=0 ; i<12 ; i++ ) // 12회 루프도는 것은 전통적인 이유때문이다.
   
{
        sum += rand_0_1();
    }
    sum -=6.0f;
    returnsum+center;
}

floatrand_0_1()
{
    return(float)rand()/RAND_MAX;
}
출처 : http://www.gpgstudy.com/forum/viewtopic.php?t=4339&highlight=%C1%A4%B1%D4%BA%D0%C6%F7

less..


난수를 많이 더하면 더할수록 그래프는 정규분포에 가깝게 나오지만 일반적으로는 12번을 사용하는군요-_-
경험적인 수치라고 합니다. 그냥 넘어갑시다=ㅁ=ㅋㅋ
그래서 적당히 6번을 더해보았습니다.
사용자 삽입 이미지
역시나 더하면 더할수록 종모양이 잘빠집니다-_-a
하지만 위의 소스가 아닌 단순히 0~1000/n 까지의 난수를 더한것이라 그런지 몇번 넘어가니 양쪽 끝이 거의 0에 가깝군요. 실제로는 7번정도의 데이터를 더해서 한다고 합니다.

이외에도 가우시안 함수를 이용한 정규분포 난수 생성기도 있습니다만...수학적으로 된것이라- _-)
설명이 불가능한 관계로 패스합니다.

반응형
반응형


#include <time.h> - 날짜와 시간에 대한 함수  ㄴ 레퍼런스 / ㅁ 내지식창고

2010/01/18 15:02

복사http://blog.naver.com/rasede/150078770618


struct tm {
        int tm_sec;     /* seconds after the minute - [0,59] */
        int tm_min;     /* minutes after the hour - [0,59] */
        int tm_hour;    /* hours since midnight - [0,23] */
        int tm_mday;    /* day of the month - [1,31] */
        int tm_mon;     /* months since January - [0,11] */ // 0부터 이므로 +1을 해줘야된다.
        int tm_year;    /* years since 1900 */ - 1900년이 기준이기때문에 2010이면 110이 저장됨.
        int tm_wday;    /* days since Sunday - [0,6] */
        int tm_yday;    /* days since January 1 - [0,365] */
        int tm_isdst;   /* daylight savings time flag */
        };

 

typedef long time_t

typedef long clock_t;

- 헤더 함수 내부에 time_t와 clock_t를 사용자 자료형으로 long으로 정의하고 있다.

 

time ( time_t time(time_t * tp) )

- 현재 시간을 가로안의 tp로 넣는다. 예를 들어 current라는 int형 변수를 선언했다면 time(&current)라고 쓴다. 그럼 cuurrent에 현재 시간이 저장된다. 시간이 잘못되어 있으면 -1을 리턴.

 

localtime ( struct tm * localtime (const time_t * tp) )

- tp로 들어온 시간을 지역시간으로 바꿔서 리턴. tm형 구조체 하나 선언해서 넣어주고 쓴다. 근데 아직 gmtime이랑 별차이를 못느끼겠음;;

 

gmtime ( struct tm * gmtime(const time_t *tp) )

- tp로 들어온 시간을 협정시계시인지 뭔지로 변환하는듯. 역시 local하고 차이를 잘 모르겠다;;

 

clock ( clock_t clock(void) )

-프로그램 실행 시작으로부터의 시간... 이라는데 이거 어떻게 쓰는거야 -_-;; 알아봐야겠다;

 

asctime ( char * asctime(const struct tm *tp) )

- 가로로 들어온 시간 구조체를 문자열로 바꿔서 반환. asctime(localtime(&current)) 이런것도 가능했다. 신기하더라. 결과는 Mon Jan 18 14:15::05 2010 이런식으로 나왔다.

 

ctime ( char * ctime (const time_t * tp) )

- 결과는 Mon Jan 18 14:15::05 2010 이런식으로 나왔다. 지역시간으로 바꿔서 문자로 하는것 같은데 위에랑 차이를 잘 모르겠다. -_-;; 위에랑 아래의 차이는 그냥 가로안에 자료형 차이?

 

difftime ( double difftime(time_t time2 , time_t time1) )

- 사용법이야 뭐 time(&1) time(&2) 해가지고 보내는건 알겠는데 언제 쓰는걸까 -_-;;; 아직 잘 모르겠다. 아. 프로그램 시작할때 1을 받고 2를 해서 프로그램이 얼마나 걸리는지 계산하려나?

 

mktime ( time_t mktime(struct tm *tp) )

- 지역시간을 표준시간으로 바꿔준다는데 바꿔도 별 차이 없던데;;

 time(&current);
 ggg=mktime(localtime(&current));

 printf("%lf", difftime(current, ggg)); ==> 결과가 그냥 0.000000 나왔다.

 

strftime

( size_t strftime(char * s, size_t smax, const char * fmt, const struct tm * tp) )

- 정해진 숫자보다 많은 수가 만들어지면 0을 리턴하고 가로 안에것을 해석하면

( 저장할 배열, 저장가능한 최대수, "저장되는 문자열", 들어오는 시간정보 )

 

char ch[128];

struct tm * local;

time(&current);
local = localtime( &current );

strftime( ch, 128, "Today is %A, day %d of %B in the year %Y.\n", local );

puts(ch);

 

그러면 출력이

              Monday        18       January                  2010

Today is    %A,    day  %i of    %B      in the year  %Y.
이런식으로 된다.

 

%a = 요일 이름의 약자 위의 예를 들어서 하자면 monday가 mon이 되어서 출력되더라.

%A = 요일 이름.

%b = 달의 이름 약자.

%b = 달의 이름

%c = 지역표기 시간 ( 01/18/10 14:57:02 이런식으로 출력됨)

%d = 날짜

%H = 시간 00~23시 까지 표시됨

%I = 시간 1~12시 까지 표시되는데 오전 오후는 표시 안되더라?

%m = 달

%M = 분

%q = 오전 오후 표시해준다.

%S = 분

%U = 일년의 몇번째 주냐

%w = 요일표시 일요일이 0으로 6까지 표시됨

%W = 일년중 몇번째 주인가 U나 W나 그게그거

%x = 지역 날짜. %c 모습에서 날짜만 보여진다고 보면됨.

%X = 지역 시간 마찬가지.

%y = 년도 현재 2010년인데 표시는 10으로 됨 00~99까지 되는듯?

%Y = 년도 2010으로 출력

%Z = 시간 지역 이름

%% = %

반응형
반응형

http://www.synch3d.com/wiki/moin/moin.cgi/template?action=LikePages


함수 템플릿

컴파일러는 각 invocation에서 사용되는 arguments의 타입에 따라서 swap의 구별된 특수화들을 인스턴스화한다: 

//template <class T> void Swap(T &a, T &b) // class와 typename에 의미의 차이는 없다. 
template <typename T> void Swap(T &a, T &b)  
{ 
 T t; t=a; a=b; b=t; 
} 

헤더와 소스로 분리하기
// swap.h 
template <typename T> void Swap( T&a, T&b); 
template <> void Swap<float>(float&a, float&b); // 이건 명시적 특수화, 확장되어 사용되는것을 미리 선언. export 키워드 없이 분리하는 법 
template <> void Swap<int>(int &a,int &b); // 이것도 마찬가지 
... 
 
// swap.cpp 
#include "swap.h" 
 
template <> void Swap<int>(int&a, int&b) // 이놈의 특수화된 템플릿 함수 
{ 
        int t; 
        t=a;a=b;b=t; 
} 
 
 
template <> void Swap<float>(float&a, float&b) // 이놈의 특수화된 템플릿 함수 
{ 
        float t; 
        t=a;a=b;b=t; 
} 

반응형
반응형


COleVariant Class 구조를 이용한 형변환  [함수/기능] 

2008/04/25 12:09

복사http://blog.naver.com/sanai108/40050415445


COleVariant 클래스 구조를 참조하여 형변환을 하자.

가령, 아래와 같은 소스가 있다면,

COleVariant varValue3((byte)111);
drs.AddNew();
drs.SetFieldValue(_T("MAP_ID"),varValue3);
drs.Update();

(byte)형변환 없이 111을 COleVariant 초기화에 사용한다면 오버로딩 문제로 에러가 발생한다.

아래 클래스 구조를 보면 일반 정수형에 관한 오버로딩된 함수가 없음을 알 수 있다.

 

class COleVariant : public tagVARIANT
{
// Constructors
public:
 COleVariant();

 COleVariant(const VARIANT& varSrc);
 COleVariant(LPCVARIANT pSrc);
 COleVariant(const COleVariant& varSrc);

 COleVariant(LPCTSTR lpszSrc);
 COleVariant(LPCTSTR lpszSrc, VARTYPE vtSrc); // used to set to ANSI string
 COleVariant(CString& strSrc);

 COleVariant(BYTE nSrc);
 COleVariant(short nSrc, VARTYPE vtSrc = VT_I2);
 COleVariant(long lSrc, VARTYPE vtSrc = VT_I4);
 COleVariant(const COleCurrency& curSrc);

 COleVariant(float fltSrc);
 COleVariant(double dblSrc);
 COleVariant(const COleDateTime& timeSrc);

 COleVariant(const CByteArray& arrSrc);
 COleVariant(const CLongBinary& lbSrc);

 COleVariant(LPCITEMIDLIST pidl);

.

.

.
}

반응형
반응형
http://exynoa.tistory.com/156



키의 상태를 확인하는

GetAsyncKeyState, GetKeyState




우선은 GetAsyncKeyState API에 대해 알아보기 전에 API의 원형을 먼저 살펴봅시다!

1
SHORT GetAsyncKeyState(int vKey)

반환값은 SHORT형이고, 첫번째 인수로는 가상 키코드가 오며, 우리가 만약 VK_UP을 넘겨주면, 방향키 중 위를 가르키는 키가 눌려있나 눌려있지 않나 확인할 수 있습니다. (키가 눌려진 상태에서는 최상위 비트(0x8000)이 1이 되며,  처음 입력되었을 때는 0x8001 비트가 1이 됩니다.)

(가상 키코드 목록을 보고싶으신 분들은 아래의 MSDN를 방문하셔서 참고하세요.)

MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx


GetAsyncKeyState의 반환값은 아래와같이 4가지로 나뉩니다. 


반환값

설명 

0 (0x0000)

이전에 누른 적이 없고 호출 시점에서 안눌린 상태

0x8000 

이전에 누른 적이 없고 호출 시점에서 눌린 상태

0x8001 

이전에 누른 적이 있고 호출 시점에서 눌린 상태

1 (0x0001)

이전에 누른 적이 있고 호출 시점에서 안눌린 상태


이전에 누른 적이 없고 호출 시점에서 눌린 상태, 즉 키가 눌려진 시점에서 0x8000을 반환합니다. 만약 이전에도 누른 적이 있고 호출 시점에서도 눌렸으면 0x8001을 반환합니다. 이전에 키를 눌렀으면 0x0001을 반환하고, 눌리지 않았다면 0x0000을 반환합니다. 혹시, GetAsyncKeyState(VK_UP) & 0x8000 이런 코드를 보신적이 있으신가요? 0x8000과 GetAsyncKeyState 반환값을 AND 연산하는 이유는 정확한 시점에서 키의 상태를 확인하기 위함입니다. 만약에 키를 눌러 GetAsyncKeyState 함수가 0x8000을 반환한다면 이를 0x8000으로 AND 연산하여 키가 눌렸을때는 0x8000이 나옵니다. 그러나 눌려진 적이 있으면 GetAsyncKeyState 함수는 0x0001을 반환한다고 했었습니다. 0x0001에다 0x8000을 AND 연산하게되면 0이 나오게 됩니다. (만약에 AND 연산하지 않았을 경우에는 눌러진 적이 있는 상태도 참이 되어 동작을 수행할 것입니다.)


이제 GetAsyncKeyState API 함수를 이용해서, 방향키(상하좌우)가 입력됨에 따라 그 방향으로 @가 그려지는 프로그램을 간단히 만들어보도록 합시다.

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
#include <stdio.h>
#include <windows.h>
#include <conio.h>
 
void gotoxy(int x, int y)
{
     COORD Cur;
     Cur.X=x;
     Cur.Y=y;
     SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),Cur);
}
 
int main(void)
{
    int x=0;
    int y=0;
 
    while(true) {
        gotoxy(x,y);
        putch('@');
 
        if(GetAsyncKeyState(VK_UP) & 0x8000) y--;
        if(GetAsyncKeyState(VK_DOWN) & 0x8000) y++;
        if(GetAsyncKeyState(VK_LEFT) & 0x8000) x--;
        if(GetAsyncKeyState(VK_RIGHT) & 0x8000) x++;
        Sleep(50);
    }
    return 0;
}

결과:


컴파일 후 프로그램을 실행시키시면 방향키 입력에 따라 @가 움직입니다. 이번에는 GetKeyState API 함수를 살펴보도록 합시다. 다음은 GetKeyState API 함수의 원형입니다.

1
SHORT GetKeyState(int nVirtKey)

GetKeyState도 반환되는 값은 SHORT형이며, 첫번째 인수도 가상 키코드가 옵니다. "그럼, GetKeyState와 GetAsyncKeyState은 똑같은게 아닌가요?"라는 궁금증이 생겨나시는 분들도 계실텐데, GetKeyState는 메세지 큐에 저장된 메시지에 따라 반환되는 값이 다릅니다. 만약에 우리가 A 키를 눌렀다는 메세지가 메세지 큐에 남아 처리되지 않을때 있을때, 키가 눌렸다고 출력될 것입니다. 반대로 GetAsyncKeyState는 메세지 큐와 상관없이 입력되는 순간 즉각적으로 읽어들여 동작합니다. GetKeyState 함수는 해당 키가 눌렸으면 음수값(0xffffff80, 0xffffff81)을 반환하고, 아닐 경우에는 0을 반환합니다. 이것 역시 이전에 누른적이 있고, 호출 시점에서는 누르지 않았다면 계속 1로 남습니다.


이번에는 GetKeyState API 함수를 이용해서 @를 움직이는 프로그램을 만들어 보도록 합시다.

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
#include <stdio.h>
#include <windows.h>
#include <conio.h>
 
void gotoxy(int x, int y)
{
     COORD Cur;
     Cur.X=x;
     Cur.Y=y;
     SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),Cur);
}
 
int main(void)
{
    int x=0;
    int y=0;
 
    while(true) {
        gotoxy(x,y);
        putch('@');
 
        if(GetKeyState(VK_UP) < 0) y--;
        if(GetKeyState(VK_DOWN) < 0) y++;
        if(GetKeyState(VK_LEFT) < 0) x--;
        if(GetKeyState(VK_RIGHT) < 0) x++;
        Sleep(50);
    }
    return 0;
}

결과:


반응형
반응형
http://blog.naver.com/ohpowel/80023953224


#include <IOMANIP>

 

또는

 

#include <iomanip.h>

 

파일의 인클루두가 필요하다.

 

 

setw() 함수 ------------------------------------------------------------------

int a = 110;

cout << setw(4) << a << endl;

 

라고 한다면 44만큼의 공간을 확보해서 출력한다는 의미로 아래와 같다.

 

printf("%4d\n", a);

 

cout       //    printf

setw(4) --->  %4d

 

 

setprecision() 함수 ---------------------------------------------------------------

부동 소숫점 정밀도를  출력할 때 쓰는 함수이다.

 

double a = 1.15;

cout << setprecision(3) << a << endl;

 

라고 하면 정수부분 포함에서 총 3개가 출력된다. 1.15가 출력된다.

아래처럼 소숫점 이하 2개를 출력하는 구문과 동일하다.


printf("%.2f\n", a);







http://narusakura.tistory.com/196




 arg 앞에 & 붙이면 참조 - 같은 주소를 가지게 된다

포인터와 같다. 하지만 포인터는 포인터변수 4바이트를 차지하고 참조는 사용하지 않는다.

참조의 단점 : 초기화할 때 들어간 값은 변하지 않는다.

참조는 const 속성을 가진다. 변경불가! 


연산자오버로딩 ...대입연산자...

연산자오버로딩 기본코드


연산자오버로딩 main



(상속+연산자오버로딩)main



***************************************************************************************************************
진수표시
C++에서 cout에 어떠한 Data를 원하는 진수형식으로 표현하기 위해 oct(8진수), dec(10진수), hex(16진수) 등을 사용합니다.(이런것을 흔히 Manipulator이라고 합니다.)

#include <iostream.h>

main()
{

   int i;
   i = 12;

  cout << "12 -> 8진수 : " << oct << i << endl;
  cout << "12 -> 10진수 : " << dec << i << endl;
  cout << "12 -> 16진수 : " << hex << i << endl;

  return 0;
}



출력되는 Data에 일정한 간격을 표시하거나 소수출력시 자리수를 맞추기 위한 함수로 C++에는 setfill(), setw(), setprecision() 함수가 있습니다.(이 세개의 함수는 iomanip.h Header File에 정의되어 있습니다.)

setw()            공백 입력 함수
setfill()            빈공간 특정표시로 채우는 함수.
setpecision()   자리수를 맞추는 함수.
#include <iostream.h>
#include <iomanip.h>

main()
{

  double d;
  d = 12.345;

 
 cout << setw(15) << "hello!" << endl;
 cout << setw(15) << setfill('-') << "hello!" << endl;
 cout << setprecision(3) << d << endl;
 return 0;
}

 



cin,cout에서 많이 쓰이는 멤버함수들이란다~ 

width( int n ) : 문자 폭을 n으로 설정
precision( int n ) : 부동 수수점의 소수부분의 자리를 n으로 설정
put( char c ) : 문자 c를 출력
get( char c) : 문자 c에 입력(공백 포함). 파일의 끝에 거짓으로 반환. int형
write( char *p, int n ) : 버퍼 p의 바이트를 출력
read( char *p, int n ) : 버퍼 p의 바이트를 출력
eof() : 스트림의 끝에 참을 반환. int형
flush() : 스트림의 플러시 


반응형
반응형

http://cafe.naver.com/codingduckhoo/521




*LRESULT

: 4바이트 정수 형이다. WIN32환경에서 메시지를 처리한 후 O/S에게 신호를 주기 위해 사용한다.
  대부분의 경우 0을 리턴하면 메시지 처리가 완료되었으니 O/S에서 더 이상 처리할 메시지가 없다는 것을 의미하며,
  -1로 O/S가 처리하던 작업을 취소시키는 경우도 있다.

*HRESULT

: 32비트 정수형으로, 다양한 메시지를 리턴한다. 
  하위16byte까지 특정 오류 코드,
  상위 16byte까지 하위 16byte 코드 이외의 정보를 표현한다.

: 좀더 자세하게는 1.심각도 코드, 2. 기능 코드, 3.오류 코드의 세 가지 필드로 나뉜다.
  1.심각도 코드 - return 정보, 경고 또는 오류를 표시하는지 여부를 저장.
  2.기능 코드    - 오류를 담당하는 시스템 영역 식별, 예외를 표시하기 위해 할당되는 고유한 숫자.
  3.오류 코드    - 예외 처리를 위한 throw 정보.
  *예외를 throw할 때, 공용 언어 런타임은 HRESULT를 COM 클라이언트에 전달한다.
   비관리 코드가 오류를 반환하면,, HRESULT는 예외로 전환되고 공용 언어 런타임에 의해 throw된다(사용자 예외처리).

: 기본 특징은 TRUE와 FALSE의 값이 반대라는 점.
  TRUE = 0, FALSE = 1.
  상위 1byte로 TRUE / FALSE를 처리한다.

: 반환형이 HRESULT라고 해서 꼭 반환값을 가질 필요는 없다. 
  return값이 없어도 된다.

: 각종 코드를 저장하여 리턴하기 때문에 디버깅 처리시에 편리하다.
  대게의 경우, 반환값에 의한 예외처리시 if문을 이용하여 넘겨 받은 return값으로 오류 메시지를 띄우지만,
  HRESULT는 예외상황을 스스로 인식하여 코드화 하기 때문에 사용자는 O / S에서 throw한 에러코드 처리만 한다.
  비관리 코드가 오류를 반환한 것이 아니고, 
  특정한 예외 처리를 할 것이 아니라면, 어떤 예외 사항이 발생했는지 사용자가 따로 throw할 필요가 없다는 것.

: HRESULT가 반환하는 값은 다음과 같다.
  (반환값이 수십 개에 달하여, 요약한다. 자세한 내용은 MSDN의 HRESULT Values를 참조)

 S_OK(Operation successful(0x00000000))
  : 때때로 Boolean TRUE 값(0x0)으로 S_FAUL와 함께 사용되며 함수가 성공하였음을 의미

  E_ABORT(Operation aborted(0x80004004))
  : 작동 정지

  E_ACCESSDENIED(General access denied error(0x80070005))
  : 일반적 접근의 금지된 에러

  E_FAIL(Unspecified failure(0x80004005))
  : 실행 실패

  E_HANDLE(Handle that is not valid(0x80070006))
  : 적합하지 않은 처리

  E_INVALIDARG(One or more arguments are not valid(0x80070057))
  : 하나 혹은 그 이상의 인자가 불분명

  E_NOINTERFACE(No such interface supported(0x80004002))
  : 요청한 인터페이스를 미지원

  E_NOTIMPL(Not implemented(0x80004001))
  : 멤버 함수에 구현 코드가 미포함

  E_OUTOFMEMORY(Failed to allocate necessary memory(0x8007000E))
  : 필요한 메모리가 할당할 수 없음

  E_POINTER(Pointer that is not valid(0x80004003))
  : 적합하지 않은 포인터

  E_UNEXPECTED(Unexpected failure(0x8000FFFF))
  : 치명적인 실패를 의미

반응형
반응형

http://blog.naver.com/xogml_blog/130144674709


인라인 함수란 무엇인가 ? 

우선 일반 함수를 알아보면, 일반 함수는 우선 매개변수를 스택에 집어넣고, 함수를 호출한다. 다시말하면


//int x86     *.cpp

int add(int a, int b) { return a + b; } 이러한 코드는

int main(void) {

add(1, 2);

return 0;

}


//int x86     *.asm

push 2

push 1

call ?add@@YAHHH@Z ; add1

add esp, 8

mov DWORD PTR _n1$[ebp], eax

이런식으로 호출된다.

또한 여기에는 적지않았지만 리턴값을 위한 스택 push, pop도 있고 라턴후 스택정리를 위한 pop도 있다..

이러한 함수 호출은 스택에 접근 하기 떄문에, 다시말하면 메모리에 접근하기 때문에 속도 저하가 생길수 있다.

이러한 스택접근, 즉 메모리 접근을 피하는 방법은 무엇이 있을까? 에서 나온 한편의 해결책이 인라인 함수이다.

위의 내용을 자세히 보려면 [calling convention] 을 보면 된다.



원리 ?

기계어를 통채로 치환한다. 즉 함수 호출없이 코드를 가져다 붙인다. ㅋ 그래서 스택접근이 없기 떄문에 메모리 접근이

없고 결국 속도면에서 이득을 얻을수 있다.



사용 ?

inline returnType functionName(argument) {

//routine...

}


ex)


//main.cpp

inline int add(int a, int b) {

return a + b;

}


int main(void) {

add(1, 2);

return 0;

}

이런식으로 사용하면 된다. 이와같이 인라인 함수를 사용해서 컴파일 하게 되면


//main.cpp

mov eax, 1

add eax, 2

mov DWORD PTR _n2$[ebp], eax

어셈 코드가 위와같이 나오게 된다. 즉 push, pop가 없으므로 성능에 향상이 있다.



문제점 1. 코드의 길이가 길어진다 ?

직관적으로 보면 메서드의 기계어를 통채로 때어다가 붙이기 때문에, 목적코드가 길어질수 있다....

라고 Effective C++이라는 책에 나오고 있지만, 오히려 목적코드를 작게 해줄수도 있다고 적혀잇다. 비교해보자

a) 일반 함수를 사용할경우 : 매개변수 push + 복귀주소 eip push + 함수호출 call

b) 인라인 함수 사용할경우 : 함수의 목적코드가 통째로 와서 붙음.


정리하면 함수의 크기가 "매개변수 push + 복귀주소 eip push + 함수호출 call" 보다 클경우 목적 코드의 길이가 길어지고

작을경우에는 오히려 목적 코드의 길이가 작아진다.


따라서 함수가 복잡할경우에는 인라인 함수의 사용을 줄여야 한다. 하지만 단순한 함수일경우 무조건 인라인이다.



문제점 2. 디버깅이 어렵다.

당연한 이야기이다. 함수 모듈화의 장점은 재활용성과 더불어 코드 가독성에 있다. 하지만 call-return 구조를 포기하되 성능을

택하였으므로 코드가 보기 어려워지고 결과적으로 디버깅이 어렵게 된다.


더불어 vs에서는 최적화 옵션때문에 release 일때만 인라인으로 처리하고(어셈을 만들고), debug 모드일경우에는 일반 함수로 처리. 



문제점 3. inline 함수는 Internal Linkage 이다.

다시말해 인라인 함수는 내부연결이다. 더 나가기전에 internal linkage에 대해 알아보면


a. Internal Linkage 

- 영역의 심볼(전역변수, 함수)이 자신을 선언한 컴파일 단위(파일)에서만 사용 가능.

-> static 전역변수, inline 함수, function template, 매크로

-> C++ 문법의 const 


b. External Linkage

- 영역의 심볼이 프로젝트 내의 모든 컴파일 단위에서 사용 가능

-> 일반 전역변수, 일반 함수

-> C 문법의 const

※ 단 C++문법의 const도 C의 const처럼 External Linkage로 쓸수 있다는 밥법이 있다.



즉 inline 함수는 내부 연결의 속성을 갖기 때문에 이런것이 불가능 하다.


//add.cpp

inline int add(int a, int b) {

return a + b;

}


//main.cpp

inline int add(int a, int b);


int main(void) {

add(1, 2);

return 0;

}

다시말해 add.cpp 에서 작성한 인라인 add함수는 자신의 컴파일 단위, 다시말해 add.cpp에서만 효력한다. 그렇다면 어떻게 해야 할까?

해법은 헤더파일, 즉 헤더파일에 인라인 함수의 선언과 구현을 다 해주고 여러 파일들에서 이 헤더를 추가하여 사용하면 된다.



문제점 4. 인라인 함수를 함수포인터로 사용 ?

볼것도 없이 우선 해보자


//main.cpp

inline int add(int a, int b) {

return a + b;

}


int main(void) {

int (*pAdd)(int, int) = &add;

pAdd(1, 2);

return 0;

}

이 코드의 목적코드를 보자. 과연 함수포인터르 받은 인라인 함수가 사용 되었을까 ? 


; 5    : int main(void) {


push ebp

mov ebp, esp

push ecx


; 6    :  int(*pAdd)(int, int) = &add;


mov DWORD PTR _pAdd$[ebp], OFFSET ?add@@YAHHH@Z ; add


; 7    :  pAdd(1, 2);


push 2

push 1

call DWORD PTR _pAdd$[ebp]

add esp, 8


; 8    :  return 0;

어 사용 안됬다. 다시말해서 인라인 함수를 함수포인터로 받을수는 있지만, 함수 포인터로 사용하면 일반 함수처럼 사용된다.

뭔상관이야 ? 할수도 있는데 이런 경우를 생각해보자.

누구나 c언어를 배울때 stdlib의 퀵소트를 사용해본적이 있을것이다. 


void qsort(void * base, size_t num, size_t size, int(* comparator)(const void *, const void *));

여기서 세번째 함수로 넘겨주는것이 함수포인터이다. C언어에서 

1. 변하지 않은 전체 알고리즘과, 변해야 하는 정책을 분리하는 것이 좋다.

2. C에서는 변하는 것을 함수 인자화, 즉 함수 포인터로 표현하면 된다.


퀵소트의 알고리즘을 보면 선택된 인자 두개를 비교하는 루틴이 있다는것을 알것이다. 이 루틴에 따라서 오름차순, 내림차순이

결정되는데, 즉 무지막지하게 저 comparator가 호출되는것이다.


간혹가다 "아 이 comparator가 많이 호출되고 단순한 함수니까 inline으로 만들자" 라는 사람이 있을텐데...

이쯤되면 눈치 챘을것이다. 함수포인터는 inline으로 사용될수 없다.


그럼 해결책은 ? 아쉽게도 C언어 에서는 없다....

단 C++에서는 함수객체라는 이름으로 해결방안이 있다. 

반응형
반응형

http://bravedog.blog.me/100005576789

프로그램 개발환경이 WIN32로 바뀌면서 의미를 잃어버린 포인터들이 있다. 이것이 near 및 far포인터이다. 하지만 예전의 소스를 해석하다 보면 심심찮게 볼 수 있다. 예전의 16비트 OS들은 메모리를 세그먼트(16bit):옵셋(16bit)의 형태로 다루었다. 옵셋을 사용하여 접근할 수 있는 메모리 공간은 64KB가 되고 세그먼트와 옵셋을 모두 사용할 경우 접근할 수 있는 메모리 공간은 총 1MB가 된다.

 

터보 C에서는 디폴트로 스몰모델(small model)의 컴파일을 사용한다. 이것은 옵셋만의 변화로 메모리에 접근하는 방식으로써 앞서 말한 바와 같이 64KB의 메모리 공간에 할당이 된다. 하지만 필요에 따라서 더 많은 메모리가 필요할 경우 터보 C에서는 near와 far키워드를 사용하여 접근할 수 있다.

 

near 포인터는 64KB용, far 포인터는 1MB용으로 스몰모델에서는 데이터의 기본형을 모두 near형으로 가정하기 때문에 near는 쓰지 않아도 된다.

 

int far *fp;              // fp는 1MB 메모리 영역용 far 포인터

int near *np;          // np는 64KB 메모리 영역용 near 포인터

 

단, far 형 포인터에 메모리번지를 대입할 때는 long형 정수를 사용해야 한다. long형 정수(4바이트)중 앞의 2바이트는 세그먼트를, 뒤쪽의 2바이트는 옵셋을 나타낸다.

 

np=0x1234;             // np 옵셋(0x1234)

fp=0x20001234L;      // fp는 세그먼트(0x2000):옵셋(0x1234)

 

뒤에 설명할 동적 메모리에 관한 함수들은 모두 far 포인터 형 함수를 별도로 가지고 있다. far 포인터 형 함수는 unix와 ansi c에서는 제공이 되지 않고 도스와 윈도우에서만 사용하였지만 최근에는 WIN32로 환경이 바뀌면서 사용하지 않게 되었다. 좀더 상세히 말하면 near포인터와 far포인터는 windef.h파일에 정의되는데 win32로 바뀌면서 빈 문장열로 처리하도록 변경되었다.

 

참고로 기존의 16비트 OS환경에서의 메모리 관련 far 포인터 형 함수의 원형들은 다음과 같다.

 

near 형far 형
mallocvoid far *farmalloc(unsigned long nbytes);
callocvoid far *farcalloc(unsigned long nunits, unsigned long nunitz);
reallocvoid far *farrealloc(void far *oldblock, unsigned long nbytes);
freevoid far *farfree(void far *block);
memsetvoid far *far_fmemset(void far *s, int c, size_t n);


http://goo.gl/PJqZm


far 포인터(far *)인 경우에는 L로 시작합니다 - LPVOID





반응형
반응형

http://www.soenlab.com/




반응형
반응형

블로그 이미지

3DMP engines

3D그래픽스 물리 수학, 프로그래밍 GPU Shader 게임엔진 알고리즘 디자인패턴 matlab etc..





#include <string>


namespace st=std;

st::string str;



처럼 사용할 수 있다 이렇게 쓰면 별 쓸모없어보이지만 아래처럼 네임스페이스가 여러개 포함될때 유용하게 쓰일 수 있다



namespace fs = boost::filesystem;




반응형
반응형


http://saelly.tistory.com/128



new 연산자 오버로딩


new, delete 연산자의 오버로딩은 다른 연산자 오버로딩과 많이 다르다!!

이 둘은 분명 연산자이다. 따라서 연산자 오버로딩이 가능하며, 이 둘을 이용해서 클래스 별로 독특한 객체의 생성과정을 정의할 수도 있다. 그런데 이 둘에 대한 연산자 오버로딩은 이전에 보았던 연산자 오버로딩과는 다소 차이가 있다.


기본적으로 제공되는 new 연산자가 하는 일


1. 메모리 공간의 할당

2. 생성자의 호출

3. 할당하고자 하는 자료형에 맞게 반환된 주소 값의 형 변환


new 연산자가 진행하는 세 가지 작업 중에서 1번에 해당하는 메모리 공간의 할당만 오버로딩 할 수 있다,


다음과 같이 오버로딩 하도록 이미 약속이 되어있다

void* operator new(size_t size) {    }

반환형은 반드시 void 포인터 형이어야 하고, 매개변수는형은 size_t이어야 한다.


※ 일반적으로 size_t 는 다음과 같이 정의되어 있다.

typedef unsigned int size_t;

그래서 0 이상의 값을 표현할 목적으로 정의된 자료형이다.


※ 크기정보는 바이트 단위로 계산되어 전달된다.




delete 연산자 오버로


delete ptr; 이것의 문장으로 객체의 소멸을 명령하면,

컴파일러는 먼저 ptr이 가리키는 객체의 소멸자를 호출한다. 그리고는 다음의 형태로 정의된 함수에 ptr에 저장된 주소 값을 전달한다.

void operator delete(void* adr){    }


따라서 delete 함수는 다음의 형태로 정의해야 한다. 즉, 소멸자는 오버로딩 된 함수가 호출되기 전에 호출이 되니 오버로딩 된 함수에서는 메모리 공간의 소멸을 책임져야 한다. 


void operator delete(void* ptr)

{

delete []ptr;

}


참고로 사용하는 컴파일러에서 void 포인터 형 대상의 delete 연산을 허용하지 않는다면, 위의 delete문을 다음과 같이 작성하면 된다.

delete []((char*)adr);



19행; 컴파일러에 의해, 필요한 메모리 공간의 크기가 바이트 단위로 계산되어서 인자로 전달되니, 크기가 1바이트인 char 단위로 메모리 공간을 할당해서 반환한다. 


Point* ptr = new Point(3, 4);


아직 객체생성이 완성된 상태가 아닌데, 어떻게 멤버함수의 호출이 가능했을까?

그것은 operator new 함수와 operator delete 함수가 static 으로 선언된 함수이기 때문이다.

비록 멤버함수의 형태로 선언을 해도 이 둘은 static 함수로 간주가 된다. 그래서 객체생성의 과정에서 호출이 가능했던 것이다.






operator new & operator new[]


new 연산자는 다음 두 가지의 형태로 오버로딩이 가능하다.


void* operator new(size_t size){    }

void* operator new[](size_t  size){    }


두번째 함수는 new 연산자를 이용한 배열할당 시 호출되는 함수이다.

Point* arr  = new Point[3]; 이런 문장을 만나면,

컴파일러는 세 개의 Point객체에 필요한 메모리 공간을 바이트 단위로 계산해서, 이를 인자로 전달하면서 new[] 함수를 호출한다.

즉, 열할당 시 호출되는 함수라는 사실을 제외하고는 operator new 함수와 차이가 없다.


마찬가지로 delete 연산자도 다음 두 가지의 형태로 오버로딩이 가능하다.


void operator delete(void* adr){    }

void operator delete[](void* adr){    }


두 번째 함수는 delete 연산자를 이용한 배열소멸 시 호출되는 함수이다.

delete []arr;


58행:  객체로 구성된 배열이기 때문에 모든 객체의 소멸자가 호출된 다음에 36행에 정의된 멤버함수(static 함수)가 호출된다.



반응형
반응형

Link : http://kldp.org/node/26526

// korText.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <iostream>
#include <string>
#include <fstream>

using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
wstring aa = L"abcde 입니다.";
wfstream filestr;

filestr.imbue(locale( "korean" ) ); // 이게 중요
filestr.open (L"C:\test.txt", wfstream::in | wfstream::out | wfstream::app);
filestr.write(aa.c_str(), static_cast<streamsize>(aa.length()));
filestr.close();

return 0;
}

반응형
반응형




년도(12) 달, 날짜, 시간, 분,초를 얻는다


// 시간얻기
__time64_t t64;
_time64(&t64);
tm* Tm;
Tm = _localtime64(&t64);
  
WCHAR Path[512];
swprintf( Path, L"%.2d%.2d%.2d %.2d:%.2d:%.2d",
 Tm->tm_year+1900-2000, Tm->tm_mon+1, Tm->tm_mday, Tm->tm_hour, Tm->tm_min, Tm->tm_sec );












블로그 이미지

3DMP engines

3D그래픽스 물리 수학, 프로그래밍 GPU Shader 게임엔진 알고리즘 디자인패턴 matlab etc..




이건 위내용을 수정한것이며 년도(2012) 달, 날짜, 시간, 분,초를 얻는다




#include <iostream>
#include <string>
using namespace std;
#include <WTypes.h>
#include <time.h>
int main()
{
__time64_t t64;
_time64(&t64);
tm* Tm;
Tm = _localtime64(&t64);

WCHAR Path[512];
swprintf( Path, L"%.2i%.2i%.2i %.2i:%.2i:%.2i", Tm->tm_year+1900, Tm->tm_mon+1, Tm->tm_mday, Tm->tm_hour, Tm->tm_min, Tm->tm_sec );


return 0;
}

반응형
반응형

http://blog.naver.com/elastica/50045305787




윈도우즈 프로그램을 개발하다 보면 날짜 및 시간 관련 처리가 필요한 경우가 많습니다.

특정 날짜 기준으로 어느 시간이 경과한 이후에 로그 파일을 지운다거나

특정 날짜에 프로그램을 실행 시킨다거나 또는 두 시간 사이의 차이점을 알아보고자 할때도

있구요..  다양한 요구 사항이 나올 수 있습니다.

 

위와 같은 요구사항에 적용될 수 있는 시간 및 날짜 관련 Tip 에 대해 정리해 보았습니다. 

1> 현재 시간 알아오기

 

아래의 두가지 코드 예제를 보시기 바랍니다.

 

첫번째 CTime::GetCurrentTime() 이 현재의 정확한 시간을 가지고 오는 함수 입니다.

CTime now1 = CTime::GetCurrentTime(); (O)

 

아래에 사용된 GetCurrentTime API 는 GetTickCount 로 대체 되었으며

시스템이 시작된 이후 경과돤 시간을 밀리세컨드로 리턴해 주는 함수입니다.

CTime now2  = GetCurrentTime(); (X)

 

CString 의 Format 을 통해 좀더 자세히 알아보겠습니다.

지금 시간이 3월 4일 오후 16:23 분 경입니다.

 

CTime::GetCurrentTime 을 사용했을 경우 정확한 현재 시간을 가져옴을 볼 수 있습니다.

 

 

*예제코드

CTime now1 = CTime::GetCurrentTime();

CTime now2  = GetCurrentTime();

 
 CString strTime1;
 
 strTime1.Format(_T("%04d-%02d-%02d %02d:%02d:%02d"),now1.GetYear(), now1.GetMonth(),now1.GetDay(),now1.GetHour(), now1.GetMinute(),now1.GetSecond());

 

 CString strTime2;

 strTime2.Format(_T("%04d-%02d-%02d %02d:%02d:%02d"),now2.GetYear(), now2.GetMonth(),now2.GetDay(),now2.GetHour(), now2.GetMinute(),now2.GetSecond());


 

2> 현재 시간 기준으로  특정 기간 전후 시간 알아오기

 

CTimeSpan  이란 클래스가 있습니다.

CTimeSpan( ) throw( );
CTimeSpan(
   __time64_t time 
) throw( );
CTimeSpan(
   LONG lDays,
   int nHours,
   int nMins,
   int nSecs 
) throw( );

 

CTimeSpan span(1,0,0,0); // 하루의 시간 간격을 의미합니다.

CTimeSpan span(0,1,0,0); // 한시간의 시간 간격을 의미합니다.

CTimeSpan span(0,0,1,0); // 1분의 시간 간격을 의미합니다.

CTimeSpan span(0,0,0,1); // 1초의 시간 간격을 의미합니다.

 

현재 시간 기준으로 하루 이후의 시간을 알고 싶은 경우 아래와 같이 코드를 작성합니다.

 

CTime now1 = CTime::GetCurrentTime();

 CTimeSpan span(1,0,0,0);

 CTime tomorrow = now1 + span;

 
 CString strTime1;
  
 strTime1.Format(_T("%04d-%02d-%02d %02d:%02d:%02d"),tomorrow.GetYear(), tomorrow.GetMonth(),tomorrow.GetDay(),
  tomorrow.GetHour(), tomorrow.GetMinute(),tomorrow.GetSecond() );

 

현재 시간은 4월 3일 16:33 분 경입니다. 정확하게 하루 이후의 날짜와 시간을 가지고 오는 것을

확인 하실 수 있습니다.

 

만약 하루 이전의 시간을 가지고 오고 싶으면 CTime tomorrow = now1  - span; 로 수정하시면 되겠죠.

 

시간 계산에 있어  범하기 쉬운 오류가 있습니다.

아래의 코드를 보시기 바랍니다.

 

CTime curTime = CTime::GetCurrentTime();
 // 스케쥴 실행시간
 CTime schTime(curTime.GetYear(), curTime.GetMonth(), curTime.GetDay() + 1, 0, 0, 0);
 CTimeSpan resultTime = schTime - curTime;

언뜻보면 문제가 없어 보이지만 curTime.GetDay() + 1 에서 에러가  발생한 가능성이 있습니다.

 

CTime 클래스의 생성자는 다음과 같습니다.

 

CTime(
   int nYear,
   int nMonth,
   int nDay,
   int nHour,
   int nMin,
   int nSec,
      int nDST = -1 
);

즉 세번째 인자는 Day 로써 최고 31까지 값이 있습니다.

 

그런데 만약 31일에 위의 코드를 실행하면 curTime.GetDay() + 1  = 32 가 되므로 예외가 발생하게

됩니다.

 

3>두 시간의 간격을 알아오는 방법

 아쉽게도 CTime 클래스는 최소 단위가 초(Second) 까지 입니다.

따라서 좀더 정밀한 시간 비교를 위해서는 적합하지가 않습니다.

 

초단위까지 동일하더라도 실제 두시간 사이에는 밀리 세컨드 단위로 차이가 나게 되어 있습니다.

이런 경우 각 시간의 간격(Gap) 을 가져오는 방법입니다.

 

FILETIME 이란 구조체가 있습니다.

 

정의는 아래와 같습니다.

typedef struct _FILETIME {
   DWORD dwLowDateTime;   /* low 32 bits  */
   DWORD dwHighDateTime;  /* high 32 bits */
} FILETIME, *PFILETIME, *LPFILETIME;

 

상위 32 비트  하위 32비트 즉 64비트 수준까지 데이터를 담을수 있는 구조입니다.

 

SYSTEMTIME 으로 설정된 시간을 FILETIME 으로 변경하는 API 로 SystemTimeToFileTime 라는 것이 있습니다.

SystemTime 을 FileTime 으로 변경시키는 함수 입니다.

 

BOOL WINAPI SystemTimeToFileTime(
  __in   const SYSTEMTIME *lpSystemTime,
  __out  LPFILETIME lpFileTime
);

아래 예제를 보시기 바랍니다.

 

 

시작 시간과 종료 시간이 절대적으로 동일하지만 않다면 두 시간 사이의 간격을

밀리 세컨드(ullDif ) 단위와 초(TimeInterval) 단위로 알아 볼수가 있습니다.

 

 SYSTEMTIME StartTime,EndTime;
  
 GetLocalTime(&StartTime);;//시작 시간

 Sleep(1000);

/* 두시간이 밀리세컨드 단위까지 동일하지 않아야 함 */

 GetLocalTime(&EndTime);;//종료시간
 
 FILETIME fTm1, fTm2;

 ULONGLONG *ullVal1, *ullVal2;
 ULONGLONG ullDif;
 float TimeInterval;
 SystemTimeToFileTime(&StartTime, &fTm1);
 SystemTimeToFileTime(&EndTime, &fTm2);

 
 ullVal1 = (ULONGLONG *)&fTm1;
 ullVal2 = (ULONGLONG *)&fTm2;

 ullDif = *ullVal2 - *ullVal1;  //100 나노 세컨드 단위

 TimeInterval = float(ullDif /10000) /1000; //다운받은 간격 초단위로 

 

4>특정 시간 이후 타이머 설정하는 방법

현재 시간 기준으로 특정 시점에 특정 작업을 실행할 필요성이

있는 경우가 있습니다.

예약 시스템이나 알람 시스템에서 사용이 될거 같네요.

두가지 예제 입니다.

 

*현재 시간 기준으로 얼마 이후에 실행하는 방법

 

CTime now = CTime::GetCurrentTime(); //현재시간
 CTime startTime;

 //오늘 기준 시작 시간에서 1일 1시간 1분 1초 후에 타이머를 실행하고 싶은 경우
 CTimeSpan sp(1,1,1,1);  
  
 startTime  = now + sp;
 CTimeSpan GapTime = startTime - now;
 
 int intTotalSeconds1 = (int)GapTime.GetTotalSeconds();

 //타이머는 밀리세컨드 단위이므로 1000을 곱해야 함
 SetTimer(0,intTotalSeconds1*1000,NULL);  

*특정 날짜에 실행하고 싶은 경우 

 

 //특정날짜에 실행하고 싶은 경우 아래 코드는 4월 10일 0:0:0 기준
 CTime startTime1(now.GetYear(), now.GetMonth(), 10, 0,0,0);

 GapTime = startTime1 - now;

 

 int intTotalSeconds2 = (int)GapTime.GetTotalSeconds();

 //타이머는 밀리세컨드 단위이므로 1000을 곱해야 함
 SetTimer(1,intTotalSeconds2*1000,NULL);  

 

반응형
반응형

함수는 스택에 쌓인다

 

함수를 호출할때 쌓이는 것은

 

1. 함수 호출 인자

2. 리턴할 주소

3. 함수내의 지역변수

 

함수가 종료될때 시스템 스택에서 위 3가지가 제거된다

 

 

그런데 재귀호출이무한히 반복되면 스택에서 제거되지 않고 계속 쌓이다 보니 오버플로우가 발생 된다

반응형
반응형

반응형

+ Recent posts