git add ZCppMain/ZMainHead.H git add ZCppMain/ZtCArray.H git add ZCppMain/ZtCObjList.H git add ZCppMain/ZMainAVL.H git add ZCppMain/ZMainHeadEx.H git add ZCppMain/ZMainXhtml.H git add ZCppMain/ZtCLoadDataBlock.H git add ZCppMain/ZtCMainChars.H git add ZCppMain/ZtCObjAVL.H git add ZCppMain/ZtCStringEx.H git add ZCppMain/ZtCTreeData.H
4344 lines
164 KiB
C++
4344 lines
164 KiB
C++
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ unsigned 정수형은 가급적이면 쓰지 말자. 일반적으로 많이 쓰는 signed 정수와의 호환이
|
|
'약간' 거슬리고 있는데, 이 '약간' 이라도 왠지 찝찝하다. 2008-09-14 03:24:00
|
|
■ 해당 namespace 에서 필요한 상수는 그 namespace 안에서 상수전용 namespace ZNsConst 를
|
|
만들고 그 안에 둔다.
|
|
|
|
해당 namespace 에서 필요한 enum 는 그 namespace 안에서 enum 전용 namespace ZNsEnum 를
|
|
만들고 그 안에 둔다. 해당 enum 형을 문자열로 돌려주는 함수는, 동일한 네임스페이스 안
|
|
에
|
|
|
|
const char* GetMSG_enum_data_type(int AI_Enum);
|
|
const char* GetMSG_enum_data_type(enum_data_type AE_Enum);
|
|
|
|
의 형태로 설계한다.
|
|
|
|
--
|
|
|
|
필요하면 ZNsEnum, ZNsConst 를 접두어로 하는 namespace 를 만들고 그 안에서 필요한 enum
|
|
자료형이나 상수형을 정의할 수 있다.
|
|
|
|
-- 2010-06-13 22:37:00
|
|
|
|
■ 해당 namespace 에서 특정 클래스에 필요한 단순히 인터페이스를 알리주는 클래스나 함수는
|
|
그 namespace 안에서 interface 전용 namespace ZNsInterface 를 만들고 그 안에 둔다. 멤버
|
|
변수가 없이 순수 interface 로만 사용되는 클래스는 'C' 가 아닌 'I' 로 시작한다.
|
|
|
|
■ 복잡한 템플릿 인수 타입 관계를 정리하기 위해 사용하는 class 에는 ZtCType 이라는 접두어
|
|
를 붙이고 모두 namespace ZNsType 에 둔다.
|
|
|
|
■ 주로 예제 용도로 작성하는 클래스는 namespace ZNsExam 에 둔다. 주로 복잡한 템플릿 인수
|
|
를 가지는 클래스에 대한 예제일 것이다.
|
|
|
|
■ 복잡한 템플릿 인수 타입 관계를 정리하기 위해 Proxy 로 사용하는 class 에는 CProxy 이라
|
|
는 접두어를 붙이고 모두 namespace ZNsIProxy 에 둔다.(Interface Proxy) 실제 Proxy 를 구
|
|
현하는 클래스는 CProxy 라는 접두어를 붙이고 namespace ZNsProxy 안에 둔다.
|
|
|
|
ZNsIProxy 와 ZNsProxy 를 다른 용도로 쓰고 있는 것이다.
|
|
|
|
■ 특정 클래스 안에서만 사용되어 사용자가 그 존재를 알 필요가 없는 클래스는
|
|
|
|
namespace ZNsHide
|
|
|
|
에 둔다.
|
|
|
|
■ 같은 이름의 일반 함수와 템플릿 함수가 있어면 좋은 상황에서 하는데, 함수를 일반 함수와
|
|
템플릿 함수로 중첩시키기가 힘들 때, 템플릿 함수를 일반함수가 속한 namespace 안에 또
|
|
다른 namespace ZNsTmpl 에 둔다.
|
|
|
|
cf) std::ZNsTmpl::FindPos();
|
|
|
|
■ 어떤 클래스(템플릿)이 거의 같은 기능을 하지만, Decoration 패턴을 사용하는 클래스와,
|
|
그렇지 않은 클래스가 쌍으로 존재할 때, Decoration 패턴을 사용하는 클래스는 주로
|
|
|
|
namespace ZNsDeco
|
|
|
|
에 둔다. Decoration 패턴은 Logic 과 View 구조에서, View 에 해당하는 클래스를, Logic
|
|
클래스 의 생성자에서 (주로) 참조로 전달받는 경우를 말한다.
|
|
|
|
■ 클래스 템플릿 설계할 때 핵심 기능만 구현하고 나머지 부분은 기초클래스나 상속클래스,
|
|
혹은 멤버가 되는 클래스로 설계할 수 있는데, 이 클래스들의 이름에 적절한 이름을 붙이기
|
|
어려운 경우에는 CHelp~ 로 시작하는 이름으로 하자. 이외에도 Business Logic 과 View 의
|
|
분리라는 뜻에서 CView~ 도 생각할 수 있다.
|
|
|
|
cf) class CHelpIOCP
|
|
|
|
■ template 으로 어떤 main class 를 디자인할 때 다른 class template 을 인수로 받는 경우
|
|
가 있겠고 이때 클래스 템플릿 인수의 instance 의 멤버를 셋팅하려면 그 template 의 모든
|
|
멤버에 대하여 public 권한을 갖게 되는 경우가 많을 것이다. 이때는 셋팅 권한을 갖는 멤
|
|
버를 외부 기초 클래스 template 으로 만들고(따라서 main class 는 이 기초클래스를 상속
|
|
한다.) 이 class 에서 friend 지정을 하면 될 것이다. 그런데 main class 도 템플릿일 것으
|
|
므로 기초 클래스가 정의되기 전에는 정의될 수 없다는 문제가 있다. 이 문제를 피하기 위
|
|
해 main class 를 상속하는 비템플릿 클래스를 선언하고 (정의는 나중으로 미루고 전방선언
|
|
만 한다.) 기초 클래스에서 이 클래스에 friend 지정을 하면 될 것이다.
|
|
|
|
아니면 public 이 아니어야 할 멤버 함수가 템플릿 설계로 인해 어쩔 수 없이 public 으로
|
|
해야 할때 No Public 을 의미하는 macro _NP_ 를 그 함수 선언과 정의 앞에 붙여주자
|
|
|
|
■ 함수가 어떤 조건에서 실행을 중지할 때, bool 값으로 표시해도 되지만 가독성을 위해서
|
|
|
|
enum std::ZNsEnum::ERun
|
|
|
|
을 사용하자.
|
|
|
|
■ 함수가 굳이 어떤 값을 리턴할 필요는 없는데, 함수의 역할이 특정 조건인지 체크해서 그
|
|
조건에 맞으면 어떤 작업을 실행한다고 할 때, 이 실행여부를 굳이 리턴하고자 한다면 bool
|
|
형 대신에, 가독성을 위해서 enum std::ZNsEnum::EAct 을 사용하자.
|
|
|
|
■ call back 함수나 이떤 이벤트마다 실행하는 함수는 접두어 'On' 을 붙이자. 어떤 컨테이너
|
|
의 각 원소마다 특정한 처리를 하는 함수에는 'Iter' 를 붙이자.
|
|
|
|
cf) CDoubleList<int>::IterElement();
|
|
|
|
'Iter' 대신에 'OnEach' 를 붙여도 좋을 것 같다.
|
|
|
|
■ 클래스의 초기와, 종료함수를 별도로 지정할 때에는 각각 접두어 Init, Fini 뒤에 적절한
|
|
이름을 붙여주자. 클래스의 초기와, 종료함수를 Init, Fini 로만 지정했더니, 나중에는 비
|
|
슷비슷한 이름이 많아서 상속할 때 상당히 햇깔렸다.
|
|
|
|
클래스의 멤버중에 단순히 멤버를 0 과 같은 초기값으로 셋팅하는 함수는 InitVar 라는 함
|
|
수명을 사용하자.
|
|
|
|
■ containter class template 는 TypeData 라는 type 을 가져야 한다. 예를 들어
|
|
|
|
CObjList<int>::TypeData
|
|
|
|
라는 접근이 가능해야 한다. 이 표기에서 int 가 TypeData 라는 것은 분명히 알 수 있으나
|
|
containter 형을 인수로 받는 템플릿에서, 그 템플릿이 어떤 자료형 (예에서는 int)에 대한
|
|
containter 인지 모르게 된다. 이것을 해결하기 위한 (템플릿을 편리하게 하기 위한)규칙이
|
|
다.
|
|
|
|
이외에도 컨테이너의 컨테이너와 같은 복잡한 컨테이너 type 을 템플릿 인수로 여러 개 갖
|
|
는 컨테이너에서 TypeData 외에 추가적인 정의를 할 수 있겠다. 이런 type 이 이름은 Type
|
|
으로 시작하는 것으로 하자.
|
|
|
|
cf) IN ZNsCPP::CStringSerial_T<>
|
|
|
|
typedef TTypeCh TypeData ;
|
|
typedef TStringType TypeCStringData ;
|
|
typedef TStringList TypeCStringList ;
|
|
|
|
※ 그런데 꼭 container class template 가 아니라 할지라도 class template 은 내부적으
|
|
로 대표 자료형 TypeData 형을 갖도록 하는 것이 좋을 것 같다. 2008-11-05 13:22:00
|
|
|
|
※ TString 에 외부 접근 형 정의를 한다면 TypeCString 이 아니라 TypeString 으로 하는
|
|
것이 좀 예쁜(?) 것 같다.
|
|
|
|
typedef TString TypeCString;
|
|
typedef TString TypeString ;
|
|
|
|
2 번 줄 코드가 좀 낳아 보이지 않을까. 2008-11-05 13:42:00
|
|
|
|
■ template 함수나 클래스에서 functor 인수는 참조로 선언하지 않는다. 아래 참고,
|
|
|
|
InputIterator& first, InputIterator& last
|
|
|
|
이라고 하지 않았다. 단순 함수나 크기가 작은 object 일 경우 느려질 수 있기 때문이다.
|
|
단 아래 for_each 예에서 InputIterator 가 클래스일 경우 복사 생성자를 꼭 가져야 한다.
|
|
|
|
template<class InputIterator, class Function>
|
|
Function for_each(InputIterator first, InputIterator last, Function f)
|
|
{
|
|
while ( first!=last ) f(*first++);
|
|
return f;
|
|
}
|
|
|
|
■ WINDOW 에서 UNICODE 로 컴파일할 경우 아래 3 개의 매크로를 추가할 것.
|
|
|
|
#define _MBCS
|
|
#define _UNICODE
|
|
#define UNICODE
|
|
|
|
■ 구 버전의 컴파일러에서 RTTI 옵션이 꺼져 있으면 헤더파일 typeinfo 을 사용할 수 없다.
|
|
|
|
|
|
■ breakpoint assembly
|
|
|
|
_asm
|
|
{
|
|
int 3;
|
|
}
|
|
|
|
■ 리눅스 core file 무제한 명령
|
|
|
|
ulimit -c unlimited
|
|
system("ulimit -c unlimited");
|
|
|
|
■ Visual C++ 2008 에 추가된 함수를 사용할려면 아래 매크로를 정의한다.
|
|
|
|
#define _WIN32_WINNT 0x0600
|
|
|
|
-- 2010-04-22 19:55:00
|
|
|
|
■ _REENTRANT_EX 매크로를 정의하면 _REENTRANT 보다 좀더 최적화된 thread-safe 함수를
|
|
사용하거나, 약간 실험적인 thread-safe 함수를 사용한다.
|
|
|
|
-- 2011-03-13 01:04:00
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
#ifndef __ZCPPMAIIN_ZMAINHEAD_H__
|
|
#define __ZCPPMAIIN_ZMAINHEAD_H__
|
|
|
|
|
|
#include <cstdio>
|
|
#include <cstdarg>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <string>
|
|
#include <climits>
|
|
#include <typeinfo>
|
|
|
|
|
|
#define _CODE_OLD_ 0
|
|
#define _CODE_BAD_ 0
|
|
#define _CODE_NEW_ 1
|
|
|
|
/*/////////////////////////////////////////////////////////////////
|
|
|
|
■ 위 매크로 _CODE_OLD_ 와 _CODE_NEW_ 등은 #if(0) 이나 #if(1) 등으
|
|
로 폐기되거나 추가된 코드를 나타냈던 것을 좀 더 직관적으로 표현
|
|
한다.
|
|
|
|
-- 2013-07-28 16:21:00
|
|
|
|
/////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
#define _COMMENT_ 0 // 주석으로 사용하는 부분.
|
|
|
|
|
|
#if defined(_WIN32) || defined(_WIN64) || defined(_WIN128) || \
|
|
defined( WIN32) || defined( WIN64) || defined( WIN128)
|
|
|
|
#ifndef _WIN
|
|
#define _WIN
|
|
#endif
|
|
|
|
#endif/*
|
|
defined(_WIN32) || defined(_WIN64) || defined(_WIN128) || \
|
|
defined( WIN32) || defined( WIN64) || defined( WIN128) */
|
|
|
|
|
|
#if defined(_WIN64) || defined( WIN64)
|
|
#ifndef __CPU_BIT_CNT__
|
|
#define __CPU_BIT_CNT__ 64
|
|
#endif
|
|
#endif /*defined(_WIN64) || defined( WIN64) */
|
|
|
|
#if defined(_WIN128) || defined( WIN128)
|
|
#ifndef __CPU_BIT_CNT__
|
|
#define __CPU_BIT_CNT__ 128
|
|
#endif
|
|
#endif /*defined(_WIN128) || defined(WIN128) */
|
|
|
|
|
|
#if defined(_WIN)
|
|
|
|
typedef signed char int8_t ;
|
|
typedef unsigned char uint8_t ;
|
|
|
|
typedef signed short int16_t;
|
|
typedef unsigned short uint16_t;
|
|
|
|
typedef signed int int32_t;
|
|
typedef unsigned int uint32_t;
|
|
|
|
typedef signed __int64 int64_t;
|
|
typedef unsigned __int64 uint64_t;
|
|
|
|
#ifndef __VISUAL_CPP_VER__
|
|
#define __VISUAL_CPP_VER__ 200800 // 끝 2 자리는 소수점 버전
|
|
#endif//__VISUAL_CPP_VER__
|
|
|
|
#elif defined(__mips__)
|
|
|
|
typedef signed char int8_t ;
|
|
typedef unsigned char uint8_t ;
|
|
|
|
typedef signed short int16_t;
|
|
typedef unsigned short uint16_t;
|
|
|
|
typedef signed int int32_t;
|
|
typedef unsigned int uint32_t;
|
|
|
|
typedef signed long long int64_t;
|
|
typedef unsigned long long uint64_t;
|
|
|
|
#else
|
|
#include <stdint.h>
|
|
#endif
|
|
|
|
|
|
#if defined(_WIN)
|
|
#define _STRUCT_PACK_
|
|
#ifndef __STD_CALL__
|
|
#define __STD_CALL__ __stdcall
|
|
#endif
|
|
#elif defined(__unix__)
|
|
#define _STRUCT_PACK_ __attribute__((packed))
|
|
#ifndef __STD_CALL__
|
|
#define __STD_CALL__
|
|
#endif
|
|
#elif defined(__linux__)
|
|
#define _STRUCT_PACK_ __attribute__((packed))
|
|
#ifndef __STD_CALL__
|
|
#define __STD_CALL__
|
|
#endif
|
|
#else
|
|
#define _STRUCT_PACK_ __attribute__((packed))
|
|
#ifndef __STD_CALL__
|
|
#define __STD_CALL__
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef _REENTRANT_EX
|
|
#ifndef _REENTRANT
|
|
#define _REENTRANT
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(_REENTRANT)
|
|
#ifndef _REENTRANT_MUTEX
|
|
#define _REENTRANT_MUTEX
|
|
#endif //_REENTRANT_MUTEX
|
|
#define _REENTRANT_BOOL_ 1
|
|
#else
|
|
#define _REENTRANT_BOOL_ 0
|
|
#endif //_REENTRANT
|
|
|
|
|
|
#ifdef _WIN
|
|
|
|
#pragma warning(disable:4503)
|
|
#pragma warning(disable:4786)
|
|
#pragma warning(disable:4996)
|
|
#pragma warning(disable:4244)
|
|
#pragma warning(disable:4267)
|
|
#pragma warning(disable:4018)
|
|
#pragma warning(disable:4312)
|
|
#pragma warning(disable:4290)
|
|
#pragma warning(disable:4076)
|
|
|
|
/*/////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ 4290 경고 : 함수 선언에 throw 가 있다.
|
|
|
|
warning C4290: 함수가 __declspec(nothrow)가 아님을 나타내려는 경우를 제외하고 C++ 예외 사양은 무시됩니다.
|
|
warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
|
|
|
|
-- 2013-07-08 02:39:00
|
|
|
|
■ 4076 경고 : wchar_t 에 unsigned 를 지정했다. 리눅스에서는 어떤 경고도 없다.
|
|
|
|
warning C4076: 'unsigned' : can not be used with type 'wchar_t'
|
|
|
|
-- 2013-07-08 02:45:00
|
|
|
|
/////////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
/*/////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ WinSock2.h 파일이 include 되기 전에, windows.h 파일이 include 돼서는 안된다.
|
|
WinSock2.h 이 필요하면, 이 파일 MainHeader 보다 먼저 include 해야 한다.
|
|
|
|
■ TCHAR.H 파일을 include 하고 _MBCS 와 _UNICODE 가 정의되어 있으면
|
|
TCHAR 이 wchar_t 으로 정의되어야 하나, VC++ 6.0 에서는 자꾸 char 로 정의된다.
|
|
|
|
-- 2006-10-12 09:53:00
|
|
|
|
/////////////////////////////////////////////////////////////////////////////*/
|
|
|
|
#include <TCHAR.H>
|
|
#include <WinSock2.h>
|
|
#include <windows.h>
|
|
|
|
// 아래 pragma 코드가 이미 CNet_Win.H 에 있는데, 필요하면 아래 주석을 제거한다.
|
|
//
|
|
// #pragma comment(lib, "ws2_32")
|
|
|
|
|
|
#ifndef _T
|
|
#define _T(X) X
|
|
#endif
|
|
|
|
|
|
#if defined(__VISUAL_CPP_VER__) && __VISUAL_CPP_VER__<200000
|
|
|
|
// VC++ 6.0 에서는 아래 선언이 필요.
|
|
// VC++ 7.0 부터는 주석처리 할 것.
|
|
|
|
typedef unsigned long ULONG_PTR ;
|
|
typedef unsigned long* PULONG_PTR;
|
|
|
|
#endif //defined(__VISUAL_CPP_VER__) && __VISUAL_CPP_VER__<200000
|
|
|
|
#else // !defined(_WIN)
|
|
|
|
#include<errno.h>
|
|
|
|
#if defined(UNICODE) || defined(_UNICODE)
|
|
#define LPCTSTR const wchar_t*
|
|
#else
|
|
#define LPCTSTR const char*
|
|
#endif
|
|
|
|
#ifndef _T
|
|
#define _T(X) X
|
|
#endif
|
|
|
|
#define LONG long
|
|
|
|
#endif // !defined(_WIN)
|
|
|
|
|
|
#if defined(_REENTRANT)
|
|
|
|
#if defined(__linux__)
|
|
|
|
// 리눅스 Multi Thread Programming 에서 ZCObjList 라든가 여러
|
|
// 자료구조에서 쓰는 동기화 뮤텍스를 위해 pthread.h 를 포함한다.
|
|
|
|
#include <pthread.h>
|
|
|
|
#elif defined(__unix__)
|
|
#include <pthread.h>
|
|
#elif defined(__sun__) // In Solaris
|
|
#include <pthread.h>
|
|
#elif defined(_WIN)
|
|
//Don't inclucde
|
|
#else
|
|
#include <pthread.h>
|
|
#endif
|
|
|
|
#endif //defined(_REENTRANT)
|
|
|
|
|
|
#ifdef _DEBUG
|
|
#include<iostream>
|
|
#include<cstdlib>
|
|
#include<fstream>
|
|
#endif
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
#define RR(RefReceive) RefReceive
|
|
|
|
// RR 메크로는 인수가 참조를 전달하고 다시 어떤 값으로 설정받는다는 것을 뜻함
|
|
|
|
|
|
#define _NP_
|
|
|
|
/* 템플릿의 멤버함수가 원래는 public 가 아니어야 하지만,
|
|
템플릿 설계상 어쩔 수 없이 public 으로 했음을 의미. No Public */
|
|
|
|
|
|
#define _VT_
|
|
|
|
// _VT_ 메크로는 주로 상속해서 사용하는 멤버함수를 의미
|
|
|
|
|
|
#define _SY_
|
|
|
|
/* 동기화(Sync) 영역에서 호출되는 함수를 의미. 따라서 이 함수안에서
|
|
같은 동기화 object 를 사용하는 함수를 호출하지 않도록 주의한다. */
|
|
|
|
#define _BETA_
|
|
|
|
/* beta 테스트 중이거나, 실제로 사용하기에는 기술적인 문제가
|
|
잠재해 있는 함수를 의미. (2011-04-03 21:37:00) */
|
|
|
|
|
|
#ifdef __CYGWIN__
|
|
#define atoll atol /*for Cygwin*/
|
|
#endif
|
|
|
|
|
|
#define __for0(IntType, i, LoopCount) for(IntType i=0; i< LoopCount; ++i)
|
|
#define __for1(IntType, i, LoopCount) for(IntType i=1; i<=LoopCount; ++i)
|
|
|
|
#define __forD0(i, LoopCount) for(i=0; i< LoopCount; ++i) // 정수형 선언이 미리 있는 경우. D 는 Declare.
|
|
#define __forD1(i, LoopCount) for(i=1; i<=LoopCount; ++i)
|
|
|
|
|
|
namespace ZNsMain
|
|
{
|
|
|
|
typedef int ZTypInt ;
|
|
typedef int ZTypIntE ; // int enum : 다른 enum 형끼리 비교할 일이 있을 때, 이 자료로 형변환한다.
|
|
typedef int ZTypIntEnum ;
|
|
typedef long ZTypIntLong ;
|
|
typedef short ZTypIntShort;
|
|
|
|
typedef int ZTypIntI ; // 정수를 가장 잘 대표할 수 있는 자료형. 필요에 따라 long 이나 short 으로 typedef 할 수도 있다.
|
|
typedef long ZTypIntL ;
|
|
typedef short ZTypIntS ;
|
|
|
|
typedef long ZTypLong ;
|
|
typedef short ZTypShort ;
|
|
|
|
typedef int8_t ZTypInt8 ;
|
|
typedef int16_t ZTypInt16 ;
|
|
typedef int32_t ZTypInt32 ;
|
|
typedef int64_t ZTypInt64 ;
|
|
|
|
typedef uint8_t ZTypUInt8 ;
|
|
typedef uint16_t ZTypUInt16 ;
|
|
typedef uint32_t ZTypUInt32 ;
|
|
typedef uint64_t ZTypUInt64 ;
|
|
|
|
typedef uint8_t ZTypIntU8 ;
|
|
typedef uint16_t ZTypIntU16 ;
|
|
typedef uint32_t ZTypIntU32 ;
|
|
typedef uint64_t ZTypIntU64 ;
|
|
|
|
#if defined(UNICODE) || defined(_UNICODE)
|
|
|
|
typedef wchar_t ZTypXCHAR ;
|
|
typedef wchar_t ZTypXChar ;
|
|
|
|
typedef wchar_t* ZTypXPChar ;
|
|
typedef const wchar_t* ZTypXCPChar ;
|
|
#else
|
|
|
|
typedef char ZTypXCHAR ;
|
|
typedef char ZTypXChar ;
|
|
|
|
typedef char* ZTypXPChar ;
|
|
typedef const char* ZTypXCPChar ;
|
|
#endif
|
|
|
|
|
|
typedef char ZTypChar ;
|
|
typedef wchar_t ZTypCharW ;
|
|
|
|
typedef const char ZTypCChar ;
|
|
typedef const wchar_t ZTypCCharW ;
|
|
|
|
typedef char* ZTypPChar ;
|
|
typedef const char* ZTypCPChar ;
|
|
typedef char* const ZTypPCChar ;
|
|
typedef const char* const ZTypCPCChar ;
|
|
|
|
typedef char* ZTypPCh ;
|
|
typedef const char* ZTypCPCh ;
|
|
typedef char* const ZTypPCCh ;
|
|
typedef const char* const ZTypCPCCh ;
|
|
|
|
typedef wchar_t* ZTypPWChar ;
|
|
typedef const wchar_t* ZTypCPWChar ;
|
|
typedef wchar_t* const ZTypPWCChar ;
|
|
typedef const wchar_t* const ZTypCPCWChar;
|
|
|
|
typedef wchar_t* ZTypPWCh ;
|
|
typedef const wchar_t* ZTypCPWCh ;
|
|
typedef wchar_t* const ZTypPWCCh ;
|
|
typedef const wchar_t* const ZTypCPCWCh ;
|
|
|
|
typedef unsigned char ZTypUChar ;
|
|
|
|
#if(0)
|
|
|
|
typedef unsigned wchar_t ZTypUWCha ;
|
|
/* VC++ 2012 에서는 여기서 4076 번 경고가 발생한다.
|
|
|
|
warning C4076: 'unsigned' : can not be used with type 'wchar_t'
|
|
|
|
Linux g++ 4.4.7 에서는 unsigned wchar_t 를 잘 인식하고 있다.
|
|
|
|
*/
|
|
#endif
|
|
|
|
typedef unsigned int ZTypUInt ;
|
|
typedef unsigned short ZTypUShort ;
|
|
typedef unsigned long ZTypULong ;
|
|
|
|
typedef unsigned char ZTypIntUChar ;
|
|
typedef unsigned int ZTypIntUInt ;
|
|
typedef unsigned short ZTypIntUShort ;
|
|
typedef unsigned long ZTypIntULong ;
|
|
|
|
typedef unsigned char ZTypIntUC ;
|
|
typedef unsigned int ZTypIntUI ;
|
|
typedef unsigned short ZTypIntUS ;
|
|
typedef unsigned long ZTypIntUL ;
|
|
|
|
#if(defined(__CPU_BIT_CNT__) && __CPU_BIT_CNT__>=64)
|
|
#ifdef _WIN
|
|
typedef __int64 ZTypLength ; // 문자열의 길이를 나타내는 자료형.
|
|
// 송수신 버퍼의 크기 자료형으로도 쓰인다.
|
|
typedef unsigned __int64 ZTypULen ;
|
|
typedef unsigned __int64 ZTypULength;
|
|
#else
|
|
typedef long ZTypLength ;
|
|
typedef unsigend long ZTypULen ;
|
|
typedef unsigend long ZTypULength ;
|
|
#endif
|
|
#else // !defined(__CPU_BIT_CNT__) || __CPU_BIT_CNT__<64
|
|
|
|
typedef long ZTypLength ;
|
|
typedef unsigend long ZTypULen ;
|
|
typedef unsigend long ZTypULength ;
|
|
|
|
#endif // !defined(__CPU_BIT_CNT__) || __CPU_BIT_CNT__<64
|
|
|
|
#ifdef _WIN
|
|
typedef __int64 ZTypLengthFile ; // 파일의 크기를 나타내는 자료형.
|
|
#else
|
|
typedef long ZTypLengthFile ; // 파일의 크기를 나타내는 자료형.
|
|
#endif
|
|
|
|
typedef ZTypLengthFile ZTypLengthF;
|
|
|
|
|
|
#ifdef _WIN
|
|
typedef __int64 ZTypLongLong ;
|
|
typedef unsigned __int64 ZTypULongLong;
|
|
|
|
typedef __int64 ZTypIntLLong ;
|
|
typedef unsigned __int64 ZTypIntULLong;
|
|
#else
|
|
typedef long long ZTypLongLong ;
|
|
typedef unsigned long long ZTypULongLong;
|
|
|
|
typedef long long ZTypIntLLong ;
|
|
typedef unsigned long long ZTypIntULLong;
|
|
#endif
|
|
|
|
|
|
typedef ZTypLongLong ZTypLLong ;
|
|
typedef ZTypULongLong ZTypULLong;
|
|
|
|
typedef ZTypLongLong ZTypIntLL ;
|
|
typedef ZTypULongLong ZTypIntULL;
|
|
|
|
|
|
#ifdef _WIN64
|
|
typedef __int64 ZTypIntPtr ; // 포인터를 표현하는 정수 크기다.
|
|
typedef unsigned __int64 ZTypIntUPtr; // 포인터를 표현하는 양의 정수 크기다.
|
|
#else
|
|
typedef long ZTypIntPtr ;
|
|
typedef unsigned long ZTypIntUPtr;
|
|
#endif
|
|
|
|
|
|
#ifdef _WIN32
|
|
typedef HANDLE ZTypeID;
|
|
#else
|
|
typedef int ZTypeID;
|
|
#endif
|
|
|
|
|
|
typedef class ZCIterEasy{} IterEasy, *IterEasyID ;
|
|
typedef const IterEasyID* IterEasyIDc;
|
|
|
|
/*///////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ typedef class CIterEasy{} *IterEasyID
|
|
|
|
CObjList<> 등에서 사용하는 반복자로 사용하는 자료형이다. 반복자를 사용할 때마
|
|
다, typedef typename std::CObjList<>::IterEasy IterEasy 등으로 길게 선언해야
|
|
하는 것이 성가셨다.
|
|
|
|
-- 2013-06-02 08:44:00
|
|
|
|
CObjList.H 등에서 관련 멤버 함수를 추가하고, CHttp.H 와 CHttp2.H 의 기존 ZCLink
|
|
를 사용하는 코드를 IterEasyID 을 사용하는 코드로 적절히 반영한 결과, 숨어 있던
|
|
버그를 발견하고 조치한 듯한, 맑은 기분을 느낄 수 있었다.
|
|
|
|
-- 2013-06-02 12:13:00
|
|
|
|
CStringEx.H 파일에도 반영했다. -- 2013-06-02 09:59:00
|
|
|
|
■ IterEasyIDc 선언을
|
|
|
|
typedef const IterEasyID IterEasyIDc;
|
|
|
|
라 하면, 천만 뜻밖에도 IterEasyIDc 의 type 이름(type().nmae() 으로 구한 값)이
|
|
IterEasyID 의 type 이름 값과 같다.
|
|
|
|
-- 2015-11-07 21:34:00
|
|
|
|
///////////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
class ZCEmpty
|
|
{
|
|
/*///////////////////////////////////////////////////////////////////////////
|
|
|
|
■ 템플릿 정의에서 비어있는 클래스를 요구하는 경우가 있다.
|
|
|
|
■ 또한 여러 개의 템플릿 인자를 가진 클래스 템플릿의 특정 인자에 대하여 부분
|
|
특수화를 하는 경우, 부분 특수화 되는 인수의 type 을, 특수화되지 않는 최초
|
|
의 템플릿 정의 부분에서 무엇으로 할 지 고민되는 경우가 있다면, 이때 고민
|
|
하지 말고 ZCEmpty 를 써버리자.
|
|
|
|
-- 2010-05-04 02:29:00
|
|
|
|
어, 근데 템플릿 인자에 void 를 사용할 수도 있다. 이것을 다소 늦게 알았는데,
|
|
그래도 비어 있는 클래스를 상속할 경우, 커파일러가 크기를 0 으로 해놓는 장점
|
|
이 있으니까 일단 그냥 둔다. 만약 void 를 사용하게 되면, void 를 템플릿 인자
|
|
로 사용하는 버전과 사용하지 않는 버전으로 항상 정의를 해주어야 하는 성가신
|
|
점이 있다.
|
|
|
|
-- 2012-09-01 17:26:00
|
|
|
|
///////////////////////////////////////////////////////////////////////////*/
|
|
};/*
|
|
class ZCEmpty*/
|
|
|
|
|
|
namespace ZNsInterface
|
|
{
|
|
// 이 이름공간안에 interface 가 되는 class (템플릿) 가 온다.
|
|
}/*
|
|
namespace ZNsInterface*/
|
|
|
|
namespace ZNsIFace
|
|
{
|
|
// 이름공간 ZNsInterface 을 짧게 ZNsIFace 으로도 표기 가능하게 한다.
|
|
|
|
using namespace ZNsInterface;
|
|
}/*
|
|
namespace ZNsIFace*/
|
|
|
|
namespace ZNsEnum
|
|
{
|
|
|
|
// ECompareResult 는 어떤 두 개의 값을 비교한 결과를 표시한다.
|
|
// ZftGetCompareCode() 나 class ZtCCompare<> 에서 사용할 것이다.
|
|
|
|
enum ZECompareResult
|
|
{
|
|
ZECompareResult_Equal= 0, // 서로 같다.
|
|
ZECompareResult_More = 1, // 왼쪽이 크다.
|
|
ZECompareResult_Less =-1 // 오른쪽이 크다.
|
|
};/*
|
|
enum ZECompareResult*/
|
|
|
|
}/*
|
|
namespace ZNsEnum*/
|
|
|
|
|
|
template<typename ZtpChar, typename ZtpiLength> ZTypIntE ZftGetCompareCode
|
|
(
|
|
const ZtpChar* ZApcLeft , ZtpiLength ZAiLenLeft ,
|
|
const ZtpChar* ZApcRight, ZtpiLength zAiLenRight
|
|
)
|
|
/*######################################################################*/
|
|
{
|
|
if(ZAiLenLeft<1 && zAiLenRight<1)
|
|
return ZNsEnum::ZECompareResult_Equal;
|
|
|
|
ZtpiLength ViLoopCnt =
|
|
(ZAiLenLeft<=zAiLenRight ? ZAiLenLeft : zAiLenRight);
|
|
|
|
__for0(ZtpiLength, i, ViLoopCnt)
|
|
{
|
|
if(ZApcLeft[i] > ZApcRight[i]) return ZNsEnum::ZECompareResult_More;
|
|
if(ZApcLeft[i] < ZApcRight[i]) return ZNsEnum::ZECompareResult_Less;
|
|
}/*
|
|
__for0(ZtpiLength, i, ViLoopCnt)*/
|
|
|
|
if(ZAiLenLeft==zAiLenRight) return ZNsEnum::ZECompareResult_Equal;
|
|
if(ZAiLenLeft> zAiLenRight) return ZNsEnum::ZECompareResult_More ;
|
|
if(ZAiLenLeft< zAiLenRight) return ZNsEnum::ZECompareResult_Less ;
|
|
|
|
return ZNsEnum::ZECompareResult_Equal;
|
|
}/*
|
|
template<typename ZtpChar, typename ZtpiLength> ZTypIntE ZftGetCompareCode
|
|
(
|
|
const ZtpChar* ZApcLeft , ZtpiLength ZAiLenLeft ,
|
|
const ZtpChar* ZApcRight, ZtpiLength zAiLenRight
|
|
)
|
|
/*######################################################################*/
|
|
|
|
|
|
/* 어떤 변수를 강제적으로 참조로 인식하게 하는 클래스. 인수를 참조로
|
|
넘어가게 하고 싶을 때 사용한다. class ZtCCheckRef 에서 사용하고 있다.
|
|
-- 2021-04-10 16:15
|
|
*/
|
|
template<typename ZtpType> class ZtCRef
|
|
{
|
|
public :
|
|
typedef ZtpType& TypeData;
|
|
typedef ZtpType TypeRaw ;
|
|
private:
|
|
TypeData mr_Data;
|
|
public :
|
|
ZtCRef(TypeData ZArTypeData) : mr_Data(ZArTypeData){}
|
|
public :
|
|
TypeData GetData(){return mr_Data;}
|
|
public :
|
|
};/*
|
|
template<typename ZtpType> class ZtCRef*/
|
|
|
|
|
|
template<typename ZtpType> inline ZtCRef<ZtpType>
|
|
ZftMakeCRef(ZtpType& ZArTypeData){ return ZtCRef<ZtpType> (ZArTypeData );}
|
|
template<typename ZtpType> inline ZtCRef<ZtpType>*
|
|
ZftMakeCPtr(ZtpType& ZArTypeData){ return (ZtCRef<ZtpType>*)(&ZArTypeData);}
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ ZftMakeCPtr() 은 인수 ZArTypeData 이 ZtCRef<ZtpType>* 인 것처럼 반환한다.
|
|
|
|
그래서 template<typename TType> class ZtCCheckRef< ZtCRef<TType>* > 에서 사용할
|
|
것이다.
|
|
|
|
-- 2025-08-07 17:16
|
|
|
|
■ 사용례는 ZCppMain/ZtCArray.H 의 IterElement() 의 주석에 있다.
|
|
|
|
■ 아래 ZftMCR() 와 ZftMCP() 는 위 함수명을 더 축약한 것이다. -- 2025-08-07 17:41
|
|
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
template<typename ZtpType> inline ZtCRef<ZtpType>
|
|
ZftMCR(ZtpType& ZArTypeData){ return ZtCRef<ZtpType> (ZArTypeData );}
|
|
template<typename ZtpType> inline ZtCRef<ZtpType>*
|
|
ZftMCP(ZtpType& ZArTypeData){ return (ZtCRef<ZtpType>*)(&ZArTypeData);}
|
|
|
|
|
|
/* template 인수에 ZtCRef 가 있으면, 해당 값을 참조로 인식하고
|
|
그렇지 않으면, 일반적인 복사해서 전달되는 값으로 인식한다.
|
|
|
|
ZtCArray.H 같은 자료 구조에서 사용하고 있다.
|
|
|
|
-- 2021-04-10 16:15
|
|
*/
|
|
template<typename TType> class ZtCCheckRef
|
|
{
|
|
public :
|
|
typedef TType TypeData;
|
|
typedef TType TypeRaw ;
|
|
private:
|
|
TypeData mr_Data;
|
|
public :
|
|
ZtCCheckRef(TypeData AR_TypeData) : mr_Data(AR_TypeData){}
|
|
public :
|
|
TypeData GetData(){return mr_Data;}
|
|
public :
|
|
static TypeData PassData(TypeData AO_Data){return AO_Data;}
|
|
};/*
|
|
template<typename TType> class ZtCCheckRef*/
|
|
|
|
|
|
/* ZtCRef 전문화 */
|
|
template<typename TType> class ZtCCheckRef< ZtCRef<TType> >
|
|
{
|
|
public :
|
|
typedef TType& TypeData;
|
|
typedef TType TypeRaw ;
|
|
typedef ZtCRef<TType> ZCRef ;
|
|
private:
|
|
TypeData mr_Data;
|
|
public :
|
|
ZtCCheckRef(TypeData AR_TypeData) : mr_Data(AR_TypeData){}
|
|
public :
|
|
TypeData GetData(){return mr_Data;}
|
|
public :
|
|
static TypeData PassData(TypeData AO_Data){return AO_Data;}
|
|
static TypeData PassData(ZCRef& AO_Data){return AO_Data.GetData();}
|
|
};/*
|
|
template<typename TType> class ZtCCheckRef< ZtCRef<TType> >*/
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////
|
|
|
|
■ ZtCRef* 전문화
|
|
|
|
아래 함수
|
|
|
|
template<typename ZtpType> inline ZtCRef<ZtpType>*
|
|
ZftMakeCPtr(ZtpType& ZArTypeData){ return (ZtCRef<ZtpType>*)(&ZArTypeData);}
|
|
|
|
를 통해, 생성된 포인터에 대해서, 정적 멤버 PassData() 로
|
|
TypeRaw* 로 강제변환하고 있다. 그래서 ZtCRef<ZtpType> 객
|
|
체의 생성없이 TypeRaw 를 참조로 다룰려고 하는 것이다.
|
|
|
|
-- 2025=08-07 17:19
|
|
|
|
//////////////////////////////////////////////////////////*/
|
|
template<typename TType> class ZtCCheckRef< ZtCRef<TType>* >
|
|
{
|
|
public :
|
|
typedef TType& TypeData;
|
|
typedef TType TypeRaw ;
|
|
typedef ZtCRef<TType> ZCRef ;
|
|
private:
|
|
TypeData mr_Data;
|
|
public :
|
|
ZtCCheckRef(TypeData AR_TypeData) : mr_Data(AR_TypeData){}
|
|
public :
|
|
TypeData GetData(){return mr_Data;}
|
|
public :
|
|
static TypeData PassData(TypeData AO_Data){return AO_Data;}
|
|
static TypeData PassData(ZCRef& AO_Data){return AO_Data.GetData();}
|
|
static TypeData PassData(ZCRef* AP_CRef)
|
|
{ return *reinterpret_cast<TypeRaw*>(AP_CRef); }
|
|
};/*
|
|
template<typename TType> class ZtCCheckRef< ZtCRef<TType>* >*/
|
|
|
|
|
|
namespace ZNsType
|
|
{
|
|
|
|
/*/////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ (주로 클래스) 템플릿에는 typename 인수를 10 개 이상 요구하는 복잡한 템플릿이 있는데 이런
|
|
템플릿의 typename 을 미리 예를 들어 명시함으로서 그 템플릿의 typename 을 지정하기 쉽도록
|
|
가이드라인을 제시하는 역할의 어떤 클래스나 데이타 타입이 올 수 있는데 이런 자료형이 이
|
|
이름공간에 온다. 어떤 데이타타입을 주로 typedef 하는 클래스라면 접두어 ZtCType 를 붙인다.
|
|
|
|
■ ZtCTypeCRTP<> 는 어떤 클래스 템플릿이 CRTP(CURIOUSLY RECURRING TEMPLATE PATTERN) 를 사용
|
|
하는지 아닌지를 알려준다. ZtCTypeCRTP<> 을 설계하지 않는다면, 같은 기능을 하기 위해, 클
|
|
래스를 2 개(CRTP 를 사용하는 클래스와, 그렇지 않은 클래스)를 만들어야 했을 것이다.
|
|
|
|
-- 2010-03-12 20:00:00
|
|
|
|
class ZtCTypeCRTP 는 상속 클래스만을 표시하고,
|
|
class ZtCTypeCRTP2 는 상속 클래스와 기반 클래스 모두를 표시한다.
|
|
|
|
어쩌면 모든 상속 클래스는 내부적으로, ZtCTypeCRTP 클래스를 갖는 원칙을 세우는 것도 좋겠
|
|
다. 그래서 상속 클래스가 CDerive0 라면, 기반 클래스에 접근하고 싶을 때,
|
|
|
|
CDerive0::ZtCTypeCRTP::TypeData
|
|
|
|
형식으로 일관성있게 접근하도록 하는 것이다. 그러자면 다중 상속의 경우에 문제가 있겠네.
|
|
|
|
-- 2021-03-25 16:01
|
|
|
|
■ 또한 이 이름 공간에 있는 클래스는 TypeData 라는 자료형을 갖는 것으로 하자.
|
|
|
|
-- 2011-10-18 21:51:00
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
template< typename TTypeChild=ZCEmpty, bool TTypebUseCRTP =false
|
|
>
|
|
class ZtCTypeCRTP ////////////////////////////////////////////////
|
|
{
|
|
public:
|
|
typedef TTypeChild TypeData;
|
|
public:
|
|
enum{ZEUseCRTP=(ZTypIntE)TTypebUseCRTP};
|
|
public:
|
|
};/*
|
|
template< typename TTypeChild=ZCEmpty, bool TTypebUseCRTP =false
|
|
>
|
|
class ZtCTypeCRTP //////////////////////////////////////////////*/
|
|
|
|
|
|
template< typename TTypeChild =ZCEmpty
|
|
, typename TTypeBase =ZCEmpty
|
|
, bool TTypebUseCRTP=false
|
|
>
|
|
class ZtCTypeCRTP2 ///////////////////////
|
|
{
|
|
public:
|
|
typedef TTypeChild TypeData;
|
|
typedef TTypeBase TypeBase;
|
|
public:
|
|
enum{ZEUseCRTP=(ZTypIntE)TTypebUseCRTP};
|
|
public:
|
|
}; /*
|
|
template< typename TTypeChild =ZCEmpty
|
|
, typename TTypeBase =ZCEmpty
|
|
, bool TTypebUseCRTP=false
|
|
>
|
|
class ZtCTypeCRTP2 /////////////////////*/
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ class ZtCTypeCRTP2<> 이 왜 필요한지, 그리고 사용례는 예전 파일 CWorkPool.H 의
|
|
'주석-CCtrlAllocWork::CRTP2'를 참고한다.
|
|
|
|
-- 2012-09-20 09:46:00
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ class ZtCTypeCRTP<> 의 단점은 상속하지 않은 class 형은 알 수 없는데, 이것을 알아내기 위해
|
|
|
|
class ZtCTypeNowCRTP<>
|
|
|
|
을 설계한다. 이 클래스의 사용예는 예전 파일 CCtrlAsyncSock.H 에 있었다.
|
|
|
|
-- 현재(2025-08-02 22:37) CCtrlAsyncSock.H 는 없다.
|
|
|
|
아래 코드에서 TAsyncServ 의 상속 클래스가
|
|
|
|
없다면, CMainServ 는 TAsyncServ 과 같고,
|
|
있다면, CMainServ0 가 상속 클래스
|
|
|
|
가 된다.
|
|
|
|
typedef typename TAsyncServ::ZtCTypeCRTP ZtCTypeCRTP ;
|
|
typedef typename ZtCTypeCRTP ::TypeData CMainServ0;
|
|
|
|
typedef std::ZNsType::ZtCTypeNowCRTP<
|
|
TAsyncServ, CMainServ0>::TypeData CMainServ ;
|
|
|
|
CMainServ& VR_CMainServ=
|
|
static_cast<CMainServ&>(ArCAsyncServ);
|
|
|
|
ZtCTypeNowCRTP<> 이 없었을 때에는 TAsyncServ 이 상속 클래스를 갖지 않은 경우, CMainServ0 이 ZCEmpty 가 되어서,
|
|
컴파일 에러를 피하기가 매우 복잡한 경우가 있었다. 지금은 상속 클래스가 없다면 그냥 자기 자신의 인터페이스를
|
|
사용하니까 컴파일 에러가 전혀 없다.
|
|
|
|
정말 멋진 기교가 아닌가. C++ 의 향기에 잠시 취해 보자. -- 2013-06-10 00:33:00
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
|
|
|
|
template<typename TTypeNow, typename TTypeChild>
|
|
class ZtCTypeNowCRTP
|
|
{ public: typedef TTypeChild TypeData; public: enum{ZEUseCRTP=1}; };
|
|
template<typename TTypeNow>
|
|
class ZtCTypeNowCRTP<TTypeNow, ZCEmpty>
|
|
{ public: typedef TTypeNow TypeData; public: enum{ZEUseCRTP=0}; };
|
|
template<typename TTypeNow>
|
|
class ZtCTypeNowCRTP<TTypeNow, void >
|
|
{ public: typedef TTypeNow TypeData; public: enum{ZEUseCRTP=0}; };
|
|
|
|
|
|
/* template 인수에 ZtCRef 가 있으면, 해당 값을 참조로 인식하고
|
|
그렇지 않으면, 일반적인 복사로 전달되는 값으로 인식한다.
|
|
|
|
class ZtCCheckRef 와는 달리, 멤버 변수를 갖지 않고, 순수하게
|
|
typedef 만 있다.
|
|
|
|
-- 2021-04-10 16:15
|
|
*/
|
|
template<typename TType> class ZtCTypeCheckRef
|
|
{
|
|
public :
|
|
typedef TType TypeData;
|
|
typedef TType TypeRaw ;
|
|
public :
|
|
};/*
|
|
template<typename TType> class ZtCTypeCheckRef*/
|
|
|
|
|
|
template<typename TType> class ZtCTypeCheckRef< ZtCRef<TType> >
|
|
{
|
|
public :
|
|
typedef TType& TypeData;
|
|
typedef TType TypeRaw ;
|
|
typedef ZtCRef<TType> ZCRef ;
|
|
public :
|
|
};/*
|
|
template<typename TType> class ZtCTypeCheckRef< ZtCRef<TType> >*/
|
|
|
|
|
|
namespace ZNsTmplParam
|
|
{
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
■ 이 이름 공간에는 어떤 템플릿의 인수가 많고, 이 인수가 몇 개의 인수가 기본
|
|
값을 갖는 경우, 끝 부분에 있는 기본값 정의 인수에 명시적인 자료형을 지정
|
|
해야 할 때, 그 이전의 기본 인수에 대해서도 일일이 지정을 해야 하는데, 이
|
|
런 불편을 일부 덜기 위해서 기본값 정의 순서가 다른 template 을 설계한다.
|
|
여기에 놓이는 클래스는 CParam~ 으로 시작하자.
|
|
|
|
■ ZNsTmplParam 이름공간은 꼭 ZNsType 에만 있을 필요는 없다. 그보다 더 적절한
|
|
장소가 있다면 그 곳에 선언하자.
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
}/*
|
|
namespace ZNsTmplParam*/
|
|
|
|
}/*
|
|
namespace ZNsType*/
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ template 인수가 Type11 까지 있음에 주의한다. 그러면 Type10 까지 전문화할 수 있는 것이다.
|
|
|
|
-- 2015-02-16 21:20:00
|
|
|
|
단, template 인수는 2개부터가 유효하다.
|
|
|
|
typedef ZtStTuple<int> CTupleInt1 는 오류다.
|
|
typedef ZtStTuple<int, int> CTupleInt2 는 정상이다.
|
|
|
|
상식적으로도 ZtStTuple<int> 으로 쓸 일은 없다. -- 2021-03-04 16:27
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
template< typename Type1 , typename Type2 =void,
|
|
typename Type3=void, typename Type4 =void,
|
|
typename Type5=void, typename Type6 =void,
|
|
typename Type7=void, typename Type8 =void,
|
|
typename Type9=void, typename Type10=void, typename Type11=void
|
|
>
|
|
struct ZtStTuple //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData TypeData1 ; /*
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData TypeData2 ; */
|
|
|
|
TypeData1 _1;
|
|
|
|
ZtStTuple(TypeData1 _T1) : _1(_T1){}
|
|
};
|
|
/*###########################################################################################*/
|
|
template< typename Type1, typename Type2 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
>
|
|
struct ZtStTuple<Type1, Type2> ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData TypeData1 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData TypeData2 ;
|
|
|
|
TypeData1 _1; TypeData2 _2;
|
|
|
|
ZtStTuple<Type1, Type2>(){}
|
|
ZtStTuple<Type1, Type2>(
|
|
TypeData1 _T1, TypeData2 _T2) : _1(_T1), _2(_T2){}
|
|
};
|
|
/*###########################################################################################*/
|
|
template< typename Type1, typename Type2, typename Type3 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
>
|
|
struct ZtStTuple<Type1, Type2, Type3> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData TypeData1 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData TypeData2 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData TypeData3 ;
|
|
|
|
TypeData1 _1; TypeData2 _2; TypeData3 _3;
|
|
|
|
ZtStTuple<Type1, Type2, Type3>(){}
|
|
ZtStTuple<Type1, Type2, Type3>(
|
|
TypeData1 _T1, TypeData2 _T2, TypeData3 _T3) :
|
|
_1(_T1), _2(_T2), _3(_T3){}
|
|
|
|
};
|
|
/*###########################################################################################*/
|
|
template< typename Type1, typename Type2, typename Type3, typename Type4 ////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
>
|
|
struct ZtStTuple<Type1, Type2, Type3, Type4> //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData TypeData1 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData TypeData2 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData TypeData3 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData TypeData4 ;
|
|
|
|
TypeData1 _1; TypeData2 _2; TypeData3 _3; TypeData4 _4;
|
|
|
|
ZtStTuple<Type1, Type2, Type3, Type4>(){}
|
|
ZtStTuple<Type1, Type2, Type3, Type4>(
|
|
TypeData1 _T1, TypeData2 _T2, TypeData3 _T3, TypeData4 _T4) :
|
|
_1(_T1), _2(_T2), _3(_T3), _4(_T4) {}
|
|
};
|
|
/*###########################################################################################*/
|
|
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5 ////////////////////////////////////////////////////////////////////////////////////////
|
|
>
|
|
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5> ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData TypeData1 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData TypeData2 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData TypeData3 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData TypeData4 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type5>::TypeData TypeData5 ;
|
|
|
|
TypeData1 _1; TypeData2 _2; TypeData3 _3; TypeData4 _4; TypeData5 _5;
|
|
|
|
ZtStTuple<Type1, Type2, Type3, Type4, Type5>(){}
|
|
ZtStTuple<Type1, Type2, Type3, Type4, Type5>(
|
|
TypeData1 _T1, TypeData2 _T2, TypeData3 _T3, TypeData4 _T4, TypeData5 _T5) :
|
|
_1(_T1), _2(_T2), _3(_T3), _4(_T4), _5(_T5){}
|
|
};
|
|
/*###########################################################################################*/
|
|
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6 ////////////////////////////////////////////////////////////////////////
|
|
>
|
|
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6> ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData TypeData1 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData TypeData2 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData TypeData3 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData TypeData4 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type5>::TypeData TypeData5 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type6>::TypeData TypeData6 ;
|
|
|
|
TypeData1 _1; TypeData2 _2; TypeData3 _3;
|
|
TypeData4 _4; TypeData5 _5; TypeData6 _6;
|
|
|
|
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6>(){}
|
|
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6>(
|
|
TypeData1 _T1, TypeData2 _T2, TypeData3 _T3 ,
|
|
TypeData4 _T4, TypeData5 _T5, TypeData6 _T6) :
|
|
_1(_T1), _2(_T2), _3(_T3), _4(_T4), _5(_T5), _6(_T6) {}
|
|
};
|
|
/*###########################################################################################*/
|
|
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7 ////////////////////////////////////////////////////////
|
|
>
|
|
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData TypeData1 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData TypeData2 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData TypeData3 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData TypeData4 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type5>::TypeData TypeData5 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type6>::TypeData TypeData6 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type7>::TypeData TypeData7 ;
|
|
|
|
TypeData1 _1; TypeData2 _2; TypeData3 _3; TypeData4 _4;
|
|
TypeData5 _5; TypeData6 _6; TypeData7 _7;
|
|
|
|
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7>(){}
|
|
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7>(
|
|
TypeData1 _T1, TypeData2 _T2, TypeData3 _T3, TypeData4 _T4,
|
|
TypeData5 _T5, TypeData6 _T6, TypeData7 _T7) :
|
|
_1(_T1), _2(_T2), _3(_T3), _4(_T4), _5(_T5), _6(_T6), _7(_T7) {}
|
|
};
|
|
/*###########################################################################################*/
|
|
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8 ////////////////////////////////////////
|
|
>
|
|
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8> //////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData TypeData1 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData TypeData2 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData TypeData3 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData TypeData4 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type5>::TypeData TypeData5 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type6>::TypeData TypeData6 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type7>::TypeData TypeData7 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type8>::TypeData TypeData8 ;
|
|
|
|
TypeData1 _1; TypeData2 _2; TypeData3 _3; TypeData4 _4;
|
|
TypeData5 _5; TypeData6 _6; TypeData7 _7; TypeData8 _8;
|
|
|
|
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8>(){}
|
|
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8>(
|
|
TypeData1 _T1, TypeData2 _T2, TypeData3 _T3, TypeData4 _T4,
|
|
TypeData5 _T5, TypeData6 _T6, TypeData7 _T7, TypeData8 _T8) :
|
|
_1(_T1), _2(_T2), _3(_T3), _4(_T4) ,
|
|
_5(_T5), _6(_T6), _7(_T7), _8(_T8) {}
|
|
};
|
|
/*###########################################################################################*/
|
|
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9 ////////////////////////
|
|
>
|
|
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9> ///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData TypeData1 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData TypeData2 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData TypeData3 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData TypeData4 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type5>::TypeData TypeData5 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type6>::TypeData TypeData6 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type7>::TypeData TypeData7 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type8>::TypeData TypeData8 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type9>::TypeData TypeData9 ;
|
|
|
|
TypeData1 _1; TypeData2 _2; TypeData3 _3; TypeData4 _4; TypeData5 _5;
|
|
TypeData6 _6; TypeData7 _7; TypeData8 _8; TypeData9 _9;
|
|
|
|
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9>(){}
|
|
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9>
|
|
(
|
|
TypeData1 _T1, TypeData2 _T2, TypeData3 _T3, TypeData4 _T4,
|
|
TypeData5 _T5, TypeData6 _T6, TypeData7 _T7, TypeData8 _T8, TypeData9 _T9
|
|
) :
|
|
_1(_T1), _2(_T2), _3(_T3), _4(_T4), _5(_T5),
|
|
_6(_T6), _7(_T7), _8(_T8), _9(_T9) {}
|
|
};
|
|
/*###########################################################################################*/
|
|
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9, typename Type10
|
|
>
|
|
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, Type10> ///////////////////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type1 >::TypeData TypeData1 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type2 >::TypeData TypeData2 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type3 >::TypeData TypeData3 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type4 >::TypeData TypeData4 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type5 >::TypeData TypeData5 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type6 >::TypeData TypeData6 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type7 >::TypeData TypeData7 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type8 >::TypeData TypeData8 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type9 >::TypeData TypeData9 ;
|
|
typedef typename ZNsType::ZtCTypeCheckRef<Type10>::TypeData TypeData10;
|
|
|
|
TypeData1 _1; TypeData2 _2; TypeData3 _3; TypeData4 _4; TypeData5 _5 ;
|
|
TypeData6 _6; TypeData7 _7; TypeData8 _8; TypeData9 _9; TypeData9 _10;
|
|
|
|
ZtStTuple<
|
|
Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, Type10>(){}
|
|
ZtStTuple<
|
|
Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, Type10>(
|
|
TypeData1 _T1, TypeData2 _T2, TypeData3 _T3, TypeData4 _T4, TypeData5 _T5 ,
|
|
TypeData6 _T6, TypeData7 _T7, TypeData8 _T8, TypeData9 _T9, TypeData10 _T10) :
|
|
_1(_T1), _2(_T2), _3(_T3), _4(_T4), _5 (_T5 ),
|
|
_6(_T6), _7(_T7), _8(_T8), _9(_T9), _10(_T10) {}
|
|
};
|
|
/*###########################################################################################*/
|
|
|
|
|
|
namespace ZNsHide
|
|
{
|
|
/* 특정 클래스 안에서만 사용되어, 사용자가 그 존재를 알 필요가 없는 클래스를 둔다. */
|
|
}/*
|
|
namespace ZNsHide*/
|
|
|
|
namespace ZNsIn
|
|
{
|
|
/*///////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ 특정 메인 클래스에 종속되어 사용되는 클래스가 있고, 메인 클래스가 생성될 때 등,
|
|
아주 잠시만 필요한 클래스가 있다면 ZNsIn~ 접두어로 시작하는 namespace 에 둔다.
|
|
ZNsHide 에 두자니 한 번은 명시적으로 사용을 하니까 Hidden 되지는 않기 때문에,
|
|
이렇게 하자. 이를테면 CIocp 클래스가 있는데, 이 클래스의 생성자에서 CHelpIocp
|
|
클래스를 인수로 받고, 그 후 CHelpIocp 는 사용자가 직접 사용할 일이 없다면 이 클
|
|
래스는 namespace ZNsInIOCP 에 둘 수 있겠다.
|
|
|
|
-- 2009-12-21 12:56:00
|
|
|
|
///////////////////////////////////////////////////////////////////////////////*/
|
|
}/*
|
|
namespace ZNsIn*/
|
|
|
|
namespace ZNsTmplParam
|
|
{
|
|
}/*
|
|
namespace ZNsTmplParam*/
|
|
|
|
namespace ZNsBase
|
|
{
|
|
// 가상 클래스도 아니고 인터페이스 전용의 함수도 아니면서
|
|
// 주로 기반 클래스로 사용되는 클래스는 여기에 둔다.
|
|
}/*
|
|
namespace ZNsBase*/
|
|
|
|
namespace ZNsSngt
|
|
{
|
|
/*////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ singleton 으로 사용되는 object 들을 가져오는 함수나 object 들은 여기에 둔다.
|
|
singleton 으로 사용되는 object 들은 여기에 두지말고, CSngt 라는 접두어를 사용할 수도 있다.
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////*/
|
|
}/*
|
|
namespace ZNsSngt*/
|
|
|
|
namespace ZNsSttc
|
|
{
|
|
/*/////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ static 멤버만을 갖는 object 들은 여기에 두거나 CSttc 라는 접두어를 사용한다.
|
|
|
|
-- 2010-03-10 19:58:00
|
|
|
|
/////////////////////////////////////////////////////////////////////////////*/
|
|
}/*
|
|
namespace ZNsSttc*/
|
|
|
|
namespace ZNsReent
|
|
{
|
|
/*////////////////////////////////////////////////////////////
|
|
|
|
■ ZNsReent : namespace Reentrant
|
|
|
|
어떤 자료 구조가 thread safe 한 경우와, 그렇지 않은 경우를
|
|
따로 구현한다면 thread safe 한 구조를 여기에 둔다.
|
|
|
|
////////////////////////////////////////////////////////////*/
|
|
}/*
|
|
namespace ZNsReent*/
|
|
|
|
namespace ZNsArg
|
|
{
|
|
/*////////////////////////////////////////////////////////////////
|
|
|
|
■ 쓰레드의 Call Back 함수와 같이 어떤 함수가 특정한 자료를 포인터
|
|
로 받고 있는데, 이 포인터가 특수한 사정으로 여러 자료형의 object
|
|
의 포인터를 받아야 할 때, 해당 object 들의 포인터를 class 로 묶
|
|
고 이 클래스 object 의 포인터로 사용하면 되는데, 이와 같은 용도
|
|
로 사용하는 클래스는 여기에 둔다.
|
|
|
|
쓰레드의 Call Back 함수라면 아예 그 함수 내부에서 내포 클래스로
|
|
정의해버리는 것이 더 좋을 것 같다.
|
|
|
|
-- 2010-01-02 22:11:00
|
|
|
|
////////////////////////////////////////////////////////////////*/
|
|
}/*
|
|
namespace ZNsArg*/
|
|
|
|
namespace ZNsDeco
|
|
{
|
|
/*////////////////////////////////////////////////////////////////
|
|
|
|
■ 어떤 클래스(템플릿)이 거의 같은 기능을 하지만, Decoration 패턴
|
|
을 사용하는 클래스와, 그렇지 않은 클래스가 쌍으로 존재할 때,
|
|
Decoration 패턴을 사용하는 클래스는 주로 namespace ZNsDeco 에 둔
|
|
다. 즉, Logic 과 View 구조에서, View 에 해당하는 클래스를 생성
|
|
자에서 (주로 참조로) 전달받는 클래스 템플릿이 주요 대상이다.
|
|
|
|
-- 2010-03-10 22:04:00
|
|
|
|
////////////////////////////////////////////////////////////////*/
|
|
}/*
|
|
namespace ZNsDeco*/
|
|
|
|
namespace ZNsView
|
|
{
|
|
/*//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ 'Logic-View 구조'(일반적으로는 Document-View 구조라고 얘기를 하는데, 그보다는
|
|
'Logic-View 구조'라고 하는 것이 더 적절한 것 같다)에서 View 에 해당하는 클래스는
|
|
여기에 놓는다. 여기에 있는 클래스는 접두어 CView 붙여도 좋을 것 같다.
|
|
|
|
접두어 CView 를 붙이지 않아도, namespace ZNsView 에 있다면 그 클래스는 View 라는
|
|
것을 알 수 있는데, 그렇다면 접두어 CView 을 붙일 것인지 말 것인지는, 그때그때 상
|
|
황에 맡기기로 하자.
|
|
|
|
-- 2011-09-11 13:50:00
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////*/
|
|
}/*
|
|
namespace ZNsView*/
|
|
|
|
namespace ZNsViewIFace
|
|
{
|
|
/*//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ 'Logic-View 구조'에서 View 에 해당하는 어떤 클래스의 interface 를 알려주는 클래스는
|
|
여기에 놓는다.
|
|
|
|
-- 2011-09-11 13:54:00
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////*/
|
|
}/*
|
|
namespace ZNsViewIFace*/
|
|
|
|
namespace ZNsCRTP
|
|
{
|
|
/*//////////////////////////////////////////////////
|
|
|
|
■ CRTP : CURIOUSLY RECURRING TEMPLATE PATTERN
|
|
|
|
CRTP 를 사용하는 클래스 템플릿은 주로 여기에 둔다.
|
|
|
|
-- 2010-03-12 13:51:00
|
|
|
|
//////////////////////////////////////////////////*/
|
|
}/*
|
|
namespace ZNsCRTP*/
|
|
|
|
namespace ZNsFunc
|
|
{
|
|
|
|
/*///////////////////////////////////////////////////////////////////////////
|
|
|
|
■ 특수한 목적으로 쓰이는 전역 템플릿 함수는 여기에 놓는다.
|
|
|
|
■ __FastMoveObj<>(Type1& AR_Type1, Type2& AR_Type2)
|
|
|
|
차기 표준에서 구현하는 RValue Reference 를 흉내낸 함수다. Move 생성자와
|
|
Move 대입연산 중 대입연산만을 흉내내는 것이며, 일반적으로 이 함수 호출후에
|
|
AR_Type2 의 크기는 0 이 되거나 줄어들 것이다.
|
|
|
|
해당 object 에 Move 대입연산이 필요하면 해당 object 를 인수로 갖는
|
|
__FastMoveObj() 함수 템플릿을 전문화하면 된다.
|
|
|
|
■ 어느 함수 func()가 인수로 전달되는 object 의 초기/종료 멤버함수를 요구하는
|
|
경우, 그때마다 해당 object class 를 선언할 때, 특정한 이름의 초기/종료 멤버
|
|
함수를 선언/정의해야 하는데, 이런 불편함을 약간이라도 감소시키기 위해, func()
|
|
에서 해당 object 를 인수로 갖는 전역함수 __Init<>(), __Fini<>() 를 호출하는
|
|
것으로 하면 다소 편해질 것이다. 그 후 필요에 따라, __Init, __Fini 템플릿을
|
|
전문화하면 된다.
|
|
|
|
■ -- 2009-08-15 19:57:00
|
|
|
|
///////////////////////////////////////////////////////////////////////////*/
|
|
|
|
template<typename Type1, typename Type2>
|
|
void __FastMoveObj(Type1& AR_Type1, Type2& AR_Type2)
|
|
{
|
|
#ifdef _DEBUG_FAST_MOVE_OBJ_
|
|
cout<<" ※※ __FastMoveObj Start : Type1="<<typeid(Type1).name()<<", Type2="<<typeid(Type2).name()<<endl;
|
|
#endif //_DEBUG_FAST_MOVE_OBJ_
|
|
|
|
AR_Type1=AR_Type2;
|
|
|
|
#ifdef _DEBUG_FAST_MOVE_OBJ_
|
|
cout<<" ※※ __FastMoveObj Close : Type2="<<typeid(Type1).name()<<", Type2="<<typeid(Type2).name()<<endl;
|
|
#endif //_DEBUG_FAST_MOVE_OBJ_
|
|
}/*
|
|
template<typename Type1, typename Type2>
|
|
void __FastMoveObj(Type& AR_Type1, Type& AR_Type2) */
|
|
|
|
template<typename Type> void __Init(Type& AR_Type)
|
|
{
|
|
#ifdef _DEBUG
|
|
cout<<"void ZNsFunc::__Init<Type>(Type&), Type="<<typeid(Type).name()<<endl;
|
|
#endif //_DEBUG
|
|
}/*
|
|
template<typename Type> void __Init(Type& AR_Type)*/
|
|
|
|
template<typename Type> void __Fini(Type& AR_Type)
|
|
{
|
|
#ifdef _DEBUG
|
|
cout<<"void ZNsFunc::__Fini<Type>(Type&), Type="<<typeid(Type).name()<<endl;
|
|
#endif //_DEBUG
|
|
}/*
|
|
template<typename Type> void __Fini(Type& AR_Type)*/
|
|
|
|
|
|
/*///////////////////////////////////////////////////////////////////////////
|
|
|
|
■ CObjAVL<> 등의 클래스에서 object 를 추가하거나 삭제할 때, 아래 중첩 함수를
|
|
각각 1 회 씩 최대 2 회 수행하게 되는데,
|
|
|
|
bool operator> (~)
|
|
bool operator==(~)
|
|
|
|
이를 꼭 1 번만 수행하도록 줄이기 위해 (클래스이지만 실은 함수인)
|
|
|
|
int ZtCCompare<>::Exec(TTypeArg1 AR_TypeArg1, TTypeArg2 AR_TypeArg2)
|
|
|
|
를 사용한다.
|
|
|
|
-- 2012-09-01 20:13:00
|
|
|
|
AR_Type1==AR_Type2 이면 ZNsEnum::ZECompareResult_Equal ,
|
|
AR_Type1>=AR_Type2 이면 ZNsEnum::ZECompareResult_Equal 이상의 값,
|
|
AR_Type1> AR_Type2 이면 ZNsEnum::ZECompareResult_More 이상의 값,
|
|
AR_Type1<=AR_Type2 이면 ZNsEnum::ZECompareResult_Equal 이하의 값,
|
|
AR_Type1< AR_Type2 이면 ZNsEnum::ZECompareResult_Less 이하의 값,
|
|
|
|
을 리턴하거나
|
|
|
|
AR_Type1>=AR_Type2 이면 ZNsEnum::ZECompareResult_Equal 이상의 값,
|
|
AR_Type1> AR_Type2 이면 ZNsEnum::ZECompareResult_Equal 보다 큰 값,
|
|
AR_Type1<=AR_Type2 이면 ZNsEnum::ZECompareResult_Equal 이하의 값,
|
|
AR_Type1< AR_Type2 이면 ZNsEnum::ZECompareResult_Equal 보다 작은 값,
|
|
|
|
을 리턴한다.
|
|
|
|
-- 2012-09-01 20:20:00
|
|
|
|
최초에는
|
|
|
|
template<typename Type1,typename Type2> __CompareObj(Type1, Type2)
|
|
|
|
라는 함수를 만들어 사용했는데, 템플릿 중첩 정의 시에 상당히 불편했었다.
|
|
분명히 문법에 맞게 썼는 것 같은데, 컴파일 에러가 자꾸 나고... 단순히 문
|
|
법에 안맞게 써서 그렇다고 한 마디 말로 표현하기에는 어려운 상황이다.
|
|
|
|
-- 2012-09-02 22:49:00
|
|
|
|
ZtCCompare<>::Exec(~) 가 template 함수로 선언되어 있는데, 이전에는 template
|
|
함수가 아니었다. 이것을 template 함수로 바꾼 이유는 ZtCCompare<> 의 template
|
|
인자에 TTypeArg1, TTypeArg2 에 구애받지 않기 위해서다. 따라서 확장성이
|
|
약간 상승한다.
|
|
|
|
-- 2012-10-09 09:14:00
|
|
|
|
///////////////////////////////////////////////////////////////////////////*/
|
|
|
|
template< typename TTypeArg1,
|
|
typename TTypeArg2,
|
|
bool TTypebCompareObj=true
|
|
>
|
|
class ZtCCompare /////////////////////////
|
|
{
|
|
public:
|
|
enum {ZEUseCompareObj=(ZTypIntE)TTypebCompareObj};
|
|
public:
|
|
|
|
template<typename TTypeArg11, typename TTypeArg22>
|
|
static ZTypInt Exec(TTypeArg11 AR_TypeArg1, TTypeArg22 AR_TypeArg2)
|
|
{
|
|
#ifdef _DEBUG_CCOMPARE_EXEC
|
|
cout<<" ※※ ZtCCompare<TTypeArg1, TTypeArg2, true> is called."<<endl;
|
|
#endif //_DEBUG_CCOMPARE_EXEC
|
|
|
|
return AR_TypeArg1.Compare(AR_TypeArg2);
|
|
}/*
|
|
template<typename TTypeArg11, typename TTypeArg22>
|
|
static ZTypInt Exec(TTypeArg11 AR_TypeArg1, TTypeArg22 AR_TypeArg2) */
|
|
|
|
public:
|
|
};/*
|
|
template< typename TTypeArg1,
|
|
typename TTypeArg2,
|
|
bool TTypebCompareObj=true
|
|
>
|
|
class ZtCCompare ///////////////////////*/
|
|
|
|
|
|
template<typename TTypeArg1, typename TTypeArg2
|
|
>
|
|
class ZtCCompare<TTypeArg1, TTypeArg2, false>
|
|
{
|
|
public:
|
|
enum {ZEUseCompareObj=0};
|
|
public:
|
|
|
|
template<typename TTypeArg11, typename TTypeArg22>
|
|
static ZTypInt Exec(TTypeArg11 AR_TypeArg1, TTypeArg22 AR_TypeArg2)
|
|
{
|
|
return ZNsEnum::ZECompareResult_Equal;
|
|
}/*
|
|
template<typename TTypeArg11, typename TTypeArg22>
|
|
static ZTypInt Exec(TTypeArg1 AR_TypeArg1, TTypeArg2 AR_TypeArg2)*/
|
|
|
|
public:
|
|
};/*
|
|
template<typename TTypeArg1, typename TTypeArg2
|
|
>
|
|
class ZtCCompare<TTypeArg1, TTypeArg2, false> */
|
|
|
|
|
|
template<> class ZtCCompare<ZTypInt, ZTypInt, true>
|
|
{
|
|
public:
|
|
enum {ZEUseCompareObj=1};
|
|
public:
|
|
|
|
static ZTypInt Exec(ZTypInt AI_Int1, ZTypInt AI_Int2)
|
|
{
|
|
#ifdef _DEBUG_CCOMPARE_EXEC
|
|
cout<<" ※※ ZtCCompare<int, int, true> is called."<<endl;
|
|
#endif //_DEBUG_CCOMPARE_EXEC
|
|
|
|
return AI_Int1 - AI_Int2 ;
|
|
}/*
|
|
static ZTypInt Exec(ZTypInt AI_Int1, ZTypInt AI_Int2)*/
|
|
|
|
public:
|
|
};/*
|
|
template<> class ZtCCompare<ZTypInt, ZTypInt, true>*/
|
|
|
|
|
|
|
|
/*/////////////////////////////////////////////
|
|
|
|
■ ZtCMoveObj<> 의 사용례는 CObjAVL.H 에 있다.
|
|
|
|
-- 2013-08-26 19:18:00
|
|
|
|
/////////////////////////////////////////////*/
|
|
|
|
template< typename TTypeArg1,
|
|
typename TTypeArg2,
|
|
bool TTypebMoveObj=true
|
|
>
|
|
class ZtCMoveObj ///////////////////////
|
|
{
|
|
public:
|
|
enum {ZEUseMoveObj=(ZTypIntE)TTypebMoveObj};
|
|
public:
|
|
|
|
template<typename TTypeArg11, typename TTypeArg22>
|
|
static void Exec(TTypeArg11 AR_TypeArg1, TTypeArg22 AR_TypeArg2)
|
|
{
|
|
#ifdef _DEBUG_MOVEOBJ_EXEC
|
|
cout<<" ※※ ZtCMoveObj<TTypeArg1, TTypeArg2, true> is called."<<endl;
|
|
#endif //_DEBUG_MOVEOBJ_EXEC
|
|
|
|
return AR_TypeArg1.Compare(AR_TypeArg2);
|
|
}/*
|
|
template<typename TTypeArg11, typename TTypeArg22>
|
|
static void Exec(TTypeArg11 AR_TypeArg1, TTypeArg22 AR_TypeArg2) */
|
|
|
|
public:
|
|
};/*
|
|
template< typename TTypeArg1,
|
|
typename TTypeArg2,
|
|
bool TTypebMoveObj=true
|
|
>
|
|
class ZtCMoveObj ////////////////////*/
|
|
|
|
|
|
template< typename TTypeArg1, typename TTypeArg2
|
|
>
|
|
class ZtCMoveObj<TTypeArg1, TTypeArg2, false> ////
|
|
{
|
|
public:
|
|
enum {ZEUseMoveObj=0};
|
|
public:
|
|
|
|
template<typename TTypeArg11, typename TTypeArg22>
|
|
static void Exec(TTypeArg11 AR_TypeArg1, TTypeArg22 AR_TypeArg2)
|
|
{
|
|
AR_TypeArg1 = AR_TypeArg2 ;
|
|
}/*
|
|
template<typename TTypeArg11, typename TTypeArg22>
|
|
static void Exec(TTypeArg11 AR_TypeArg1, TTypeArg22 AR_TypeArg2) */
|
|
|
|
public:
|
|
};/*
|
|
template< typename TTypeArg1, typename TTypeArg2
|
|
>
|
|
class ZtCMoveObj<TTypeArg1, TTypeArg2, false> ##*/
|
|
|
|
}/*
|
|
namespace ZNsFunc*/
|
|
|
|
|
|
namespace ZNsTmplChain
|
|
{
|
|
|
|
/*////////////////////////////////////////////////////////////
|
|
|
|
■ ZtCTmplChain<> 와 유사한 인터페이스를 이용하여, 마치 chain
|
|
처럼 호출하는 구조를 갖는 클래스를 여기에 둔다.
|
|
|
|
-- 2011-08-05 21:16:00
|
|
|
|
사용례는 CMainChars.H 의
|
|
|
|
TTypeLength CSearchCursor_T<>::GetLengthByTmplChain(~)
|
|
|
|
함수를 참고한다.
|
|
|
|
-- 2011-08-06 23:51:00
|
|
|
|
////////////////////////////////////////////////////////////*/
|
|
|
|
template< typename TTypeNow, typename TTypeNext
|
|
>
|
|
class ZtCTmplChain ////////////////////////////
|
|
{
|
|
public :
|
|
typedef TTypeNow ZCObjNow ;
|
|
typedef TTypeNext ZCObjNext;
|
|
public :
|
|
enum{ZENextObjNo =ZCObjNext::ENextObjNo+1};
|
|
enum{ZEBoolNextObj=1 };
|
|
private:
|
|
TTypeNow mo_ZCObjNow ;
|
|
TTypeNext mo_ZCObjNext;
|
|
public :
|
|
ZCObjNow& GetNowObj () {return mo_ZCObjNow ;}
|
|
ZCObjNext& GetNextObj() {return mo_ZCObjNext;}
|
|
/*#####################################################*/
|
|
const ZCObjNow& GetNowObj () const{return mo_ZCObjNow ;}
|
|
const ZCObjNext& GetNextObj() const{return mo_ZCObjNext;}
|
|
public:
|
|
};/*
|
|
template< typename TTypeNow, typename TTypeNext
|
|
>
|
|
class ZtCTmplChain //////////////////////////*/
|
|
|
|
|
|
template<typename TTypeNow> class ZtCTmplChain<TTypeNow, ZCEmpty>
|
|
{
|
|
public :
|
|
typedef TTypeNow ZCObjNow ;
|
|
typedef TTypeNow ZCObjNext;
|
|
public :
|
|
enum{ZENextObjNo =1};
|
|
enum{ZEBoolNextObj=0};
|
|
private:
|
|
ZCObjNow mo_ZCObjNow;
|
|
public :
|
|
ZCObjNow& GetNowObj () {return mo_ZCObjNow;}
|
|
ZCObjNext& GetNextObj() {return mo_ZCObjNow;}
|
|
/*####################################################*/
|
|
const ZCObjNow& GetNowObj () const{return mo_ZCObjNow;}
|
|
const ZCObjNext& GetNextObj() const{return mo_ZCObjNow;}
|
|
public:
|
|
};/*
|
|
template<typename TTypeNow> class ZtCTmplChain<TTypeNow, ZCEmpty> */
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ ZtCTmplTreeChain<> 와 유사한 인터페이스를 이용하여, 마치 chain 의 tree 처럼
|
|
호출하는 구조를 갖는 클래스를, ZtCTmplChain<> 와 같은 namespace 에 둔다.
|
|
|
|
-- 2011-10-04 00:46:00
|
|
|
|
일종의 2진 트리 형태인데, GetNextObj2() 멤버로 호출하는 노드를 따라서 먼저
|
|
처리를 끝내는지, 아니면 GetNextObj() 멤버로 호출하는 노드를 따라서 먼저 처리할
|
|
것인지는 경우에 따라 다르다. 일반적으로는 GetNextObj2() 멤버로 호출하는 노드를
|
|
따라서 먼저 처리를 하는 것으로 정한다.
|
|
|
|
-- 2011-10-04 21:01:00
|
|
|
|
사용례는 CMainChars.H 의
|
|
|
|
TTypeLength CSearchCursor_T<>::GetLengthByTmplTreeChain(~)
|
|
|
|
함수를 참고한다.
|
|
|
|
-- 2011-10-04 00:53:00
|
|
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
|
|
template< typename TTypeNow ,
|
|
typename TTypeNext ,
|
|
typename TTypeNext2
|
|
>
|
|
class ZtCTmplTreeChain /////////
|
|
{
|
|
public :
|
|
enum{ZENextObjNo =TTypeNext ::ENextObjNo +1};
|
|
enum{ZENextObjNo2 =TTypeNext2::ENextObjNo2+1};
|
|
enum{ZEBoolNextObj =1};
|
|
enum{ZEBoolNextObj2=1};
|
|
enum{ZEObjChainCnt =TTypeNext::EObjChainCnt+TTypeNext2::EObjChainCnt+2};
|
|
public :
|
|
typedef TTypeNow ZCObjNow ;
|
|
typedef TTypeNext ZCObjNext ;
|
|
typedef TTypeNext2 ZCObjNext2;
|
|
private:
|
|
ZCObjNow mo_ZCObjNow ;
|
|
ZCObjNext mo_ZCObjNext ;
|
|
ZCObjNext2 mo_ZCObjNext2;
|
|
public :
|
|
ZCObjNow& GetNowObj () {return mo_ZCObjNow ;}
|
|
ZCObjNext& GetNextObj () {return mo_ZCObjNext ;}
|
|
ZCObjNext2& GetNextObj2() {return mo_ZCObjNext2;}
|
|
/*########################################################*/
|
|
const ZCObjNow& GetNowObj () const{return mo_ZCObjNow ;}
|
|
const ZCObjNext& GetNextObj () const{return mo_ZCObjNext ;}
|
|
const ZCObjNext2& GetNextObj2() const{return mo_ZCObjNext2;}
|
|
public :
|
|
};/*
|
|
template< typename TTypeNow ,
|
|
typename TTypeNext ,
|
|
typename TTypeNext2
|
|
>
|
|
class ZtCTmplTreeChain ///////*/
|
|
|
|
|
|
template< typename TTypeNow, typename TTypeNext
|
|
>
|
|
class ZtCTmplTreeChain<TTypeNow, TTypeNext, ZCEmpty>
|
|
{
|
|
public :
|
|
enum{ZENextObjNo =TTypeNext::ENextObjNo +1};
|
|
enum{ZENextObjNo2 =0 };
|
|
enum{ZEBoolNextObj =1 };
|
|
enum{ZEBoolNextObj2=0 };
|
|
enum{ZEObjChainCnt =TTypeNext::EObjChainCnt+1};
|
|
public :
|
|
typedef TTypeNow ZCObjNow ;
|
|
typedef TTypeNext ZCObjNext ;
|
|
typedef TTypeNext ZCObjNext2; // interface 호환을 위해서만 존재.
|
|
private:
|
|
ZCObjNow mo_ZCObjNow ;
|
|
ZCObjNext mo_ZCObjNext;
|
|
public :
|
|
ZCObjNow& GetNowObj () {return mo_ZCObjNow ;}
|
|
ZCObjNext& GetNextObj () {return mo_ZCObjNext;}
|
|
ZCObjNext2& GetNextObj2() {return mo_ZCObjNext;} // interface 호환을 위해서만 존재.
|
|
/*#######################################################*/
|
|
const ZCObjNow& GetNowObj () const{return mo_ZCObjNow ;}
|
|
const ZCObjNext& GetNextObj () const{return mo_ZCObjNext;}
|
|
const ZCObjNext2& GetNextObj2() const{return mo_ZCObjNext;} // interface 호환을 위해서만 존재.
|
|
public :
|
|
};/*
|
|
template< typename TTypeNow, typename TTypeNext
|
|
>
|
|
class ZtCTmplTreeChain<TTypeNow, TTypeNext, ZCEmpty> */
|
|
|
|
template< typename TTypeNow, typename TTypeNext2
|
|
>
|
|
class ZtCTmplTreeChain<TTypeNow, ZCEmpty, TTypeNext2>
|
|
{
|
|
public :
|
|
enum{ZENextObjNo =0 };
|
|
enum{ZENextObjNo2 =TTypeNext2::ENextObjNo2 +1 };
|
|
enum{ZEBoolNextObj =0 };
|
|
enum{ZEBoolNextObj2=1 };
|
|
enum{ZEObjChainCnt =TTypeNext2::EObjChainCnt+1 };
|
|
public :
|
|
typedef TTypeNow ZCObjNow ;
|
|
typedef TTypeNext2 ZCObjNext ; // interface 호환을 위해서만 존재.
|
|
typedef TTypeNext2 ZCObjNext2;
|
|
private:
|
|
ZCObjNow mo_ZCObjNow ;
|
|
ZCObjNext2 mo_ZCObjNext2;
|
|
public :
|
|
ZCObjNow& GetNowObj () {return mo_ZCObjNow ;}
|
|
ZCObjNext& GetNextObj () {return mo_ZCObjNext2;} // interface 호환을 위해서만 존재.
|
|
ZCObjNext2& GetNextObj2() {return mo_ZCObjNext2;}
|
|
/*########################################################*/
|
|
const ZCObjNow& GetNowObj () const{return mo_ZCObjNow ;}
|
|
const ZCObjNext& GetNextObj () const{return mo_ZCObjNext2;} // interface 호환을 위해서만 존재.
|
|
const ZCObjNext2& GetNextObj2() const{return mo_ZCObjNext2;}
|
|
public :
|
|
};/*
|
|
template< typename TTypeNow , typename TTypeNext2
|
|
>
|
|
class ZtCTmplTreeChain<TTypeNow, ZCEmpty, TTypeNext2> */
|
|
|
|
template< typename TTypeNow ////////////////////
|
|
>
|
|
class ZtCTmplTreeChain<TTypeNow, ZCEmpty, ZCEmpty>
|
|
{
|
|
public :
|
|
enum{ZENextObjNo =0};
|
|
enum{ZENextObjNo2 =0};
|
|
enum{ZEBoolNextObj =0};
|
|
enum{ZEBoolNextObj2=0};
|
|
enum{ZEObjChainCnt =1};
|
|
public :
|
|
typedef TTypeNow ZCObjNow ;
|
|
typedef ZCObjNow ZCObjNext ; // interface 호환을 위해서만 존재.
|
|
typedef ZCObjNow ZCObjNext2; // interface 호환을 위해서만 존재.
|
|
private:
|
|
ZCObjNow mo_ZCObjNow;
|
|
public :
|
|
ZCObjNow& GetNowObj () {return mo_ZCObjNow;}
|
|
ZCObjNext& GetNextObj () {return mo_ZCObjNow;} // interface 호환을 위해서만 존재.
|
|
ZCObjNext2& GetNextObj2() {return mo_ZCObjNow;} // interface 호환을 위해서만 존재.
|
|
/*######################################################*/
|
|
const ZCObjNow& GetNowObj () const{return mo_ZCObjNow;} // interface 호환을 위해서만 존재.
|
|
const ZCObjNext& GetNextObj () const{return mo_ZCObjNow;} // interface 호환을 위해서만 존재.
|
|
const ZCObjNext2& GetNextObj2() const{return mo_ZCObjNow;} // interface 호환을 위해서만 존재.
|
|
public :
|
|
};/*
|
|
template< typename TTypeNow ////////////////////
|
|
>
|
|
class ZtCTmplTreeChain<TTypeNow, ZCEmpty, ZCEmpty>
|
|
*/
|
|
}/*
|
|
namespace ZNsTmplChain*/
|
|
|
|
|
|
/*///////////////////////////////////////////////////////////////////
|
|
|
|
■ 함수가 어떤 조건에서 실행을 중지할 때,
|
|
bool 값으로 표시해도 되지만 가독성을 위해서 enum ZERun 을 사용하자.
|
|
|
|
■ enum ZERun 의 값을 포함해서 에러 상태를 표현하고 싶을 때에는,
|
|
enum ZERunEx 를 사용하자.
|
|
|
|
-- 2011-09-27 05:37:00
|
|
|
|
///////////////////////////////////////////////////////////////////*/
|
|
|
|
namespace ZNsEnum
|
|
{
|
|
|
|
enum ZERun
|
|
{
|
|
ZERun_NO, // 실행 중지
|
|
ZERun_OK // 실행 계속
|
|
};/*
|
|
enum ZERun*/
|
|
|
|
enum ZERunEx
|
|
{
|
|
ZERunEx_NO, // 실행 중지
|
|
ZERunEx_OK, // 실행 계속
|
|
ZERunEx_Err // 실행 에러
|
|
};/*
|
|
enum ZERun*/
|
|
|
|
enum ZEAct
|
|
{
|
|
ZEAct_NO, // (함수 등이) 어떤 조건에 맞지 않아서 아무 짓도 하지 않았다.
|
|
ZEAct_OK // (함수 등이) 어떤 조건에 맞아서 지정된 처리를 하였다.
|
|
};/*
|
|
enum ZEAct*/
|
|
|
|
enum ZEActEx
|
|
{
|
|
ZEActEx_NO, // (함수 등이) 어떤 조건에 맞지 않아서 아무 짓도 하지 않았다.
|
|
ZEActEx_OK, // (함수 등이) 어떤 조건에 맞아서 지정된 처리를 하였다.
|
|
ZEActEx_Err // (함수 등이) 수행 중에 에러가 발생하였다.
|
|
};/*
|
|
enum ZEAct*/
|
|
|
|
enum ZEThrowFinally
|
|
{
|
|
ZEThrowFinally_NO,
|
|
ZEThrowFinally_OK
|
|
};/*
|
|
enum ZEThrowFinally*/
|
|
|
|
/*////////////////////////////////////////////////
|
|
|
|
■ 타 언어의 throw ~ catch ~ finally 를 흉내낼 때
|
|
EThrowFinally 예외를 던진다.
|
|
|
|
////////////////////////////////////////////////*/
|
|
|
|
}/*
|
|
namespace ZNsEnum*/
|
|
|
|
|
|
using ZNsEnum::ZERun ;
|
|
using ZNsEnum::ZERun_NO ;
|
|
using ZNsEnum::ZERun_OK ;
|
|
|
|
using ZNsEnum::ZERunEx ;
|
|
using ZNsEnum::ZERunEx_NO ;
|
|
using ZNsEnum::ZERunEx_OK ;
|
|
using ZNsEnum::ZERunEx_Err;
|
|
|
|
|
|
namespace ZNsInterface
|
|
{
|
|
|
|
/*////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ class ZIDelgtMSG 는 C# 의 delegate 삼아서 만든 클래스.
|
|
|
|
어느 object 가 하나 이상의 다른 object 에게 어떤 메시지를 전달하고 싶을 때, 메시지를
|
|
전송하는 object 는, 수신하는 object 의 기반클래스 ZIDelgtMSG 의 참조나 포인터를 멤버
|
|
로 가지고 있다가, ZIDelgtMSG::SendMSG() 나 ZIDelgtMSG::RecvMSG() 을 호출하면 된다.
|
|
|
|
■ COM 개념을 상당부분 포함하고 있다. 간단하게 COM 대용으로 써도 될 듯 하다.
|
|
|
|
-- 2009-03-08 02:26:00
|
|
|
|
■ class ZIDelgtMSG 를 상속하여 추가 멤버함수를 가진 인터페이스를 구현하는 클래스일 경우
|
|
에는 namespace ZNsInterface 에 두지 말고 namespace ZNsIDelgt 에 두자.
|
|
|
|
-- 2009-03-08 19:17:00
|
|
|
|
■ A, B, C 클래스가 서로의 존재를 알아야 한다고 할 때도 사용할 수 있겠다. 그런데 이런 경
|
|
우는 굳이 ZIDelgtMSG 를 사용하지 말고, 단순 가상 함수 클래스를 사용해도 된다. 그게 더
|
|
간단할 것이다. 그래도 ZIDelgtMSG 를 사용한다면, interface 의 일관성을 얻을 수 있다는 게
|
|
장점이 될 수 있다.
|
|
|
|
-- 2010-03-13 22:28:00
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////*/
|
|
|
|
class ZIDelgtMSG
|
|
{
|
|
public:
|
|
enum ZEIMsg{ZEIMsg_NO=0, ZEIMsg_OK=1};
|
|
public:
|
|
|
|
virtual ~ZIDelgtMSG(){}
|
|
|
|
virtual ZTypLLong GetTypeID() const
|
|
{
|
|
return 0;
|
|
}/*
|
|
virtual ZTypLLong GetTypeID() const*/
|
|
|
|
virtual const char* GetTypeName() const
|
|
{
|
|
return 0;
|
|
}/*
|
|
virtual const char* GetTypeID() const*/
|
|
|
|
virtual ZTypLLong GetIMSGPtrOfID(ZTypLLong AI_TypeID, ZIDelgtMSG*& APR_ZIDelgtMSG)
|
|
{
|
|
APR_ZIDelgtMSG=0; return ZEIMsg_OK;
|
|
}/*
|
|
virtual ZTypLLong GetIMSGPtrOfID(ZTypLLong AI_TypeID, ZIDelgtMSG*R APR_ZIDelgtMSG)*/
|
|
|
|
virtual ZTypIntPtr SendMSG(ZIDelgtMSG& ArZIDelgtMSG, ZTypIntI AI_MsgNo, const char* ApcMsgData, ZTypIntI AI_MsgLen, void* AP_Void=0, ...)
|
|
{
|
|
return ZEIMsg_OK;
|
|
}/*
|
|
virtual ZTypIntPtr SendMSG(ZIDelgtMSG& ArZIDelgtMSG, ZTypIntI AI_MsgNo, const char* ApcMsgData, ZTypIntI AI_MsgLen,void* AP_Void=0, ...)*/
|
|
|
|
virtual ZTypIntPtr RecvMSG(ZTypIntI AI_MsgNo, const char* ApcMsgData, ZTypLength AI_MsgLen, void* AP_Void=0, ...)
|
|
{
|
|
return ZEIMsg_OK;
|
|
}/*
|
|
virtual ZTypIntPtr RecvMSG(ZTypIntI AI_MsgNo, const char* ApcMsgData, ZTypLength AI_MsgLen, void* AP_Void=0, ...)*/
|
|
|
|
public:
|
|
};/*
|
|
class ZIDelgtMSG*/
|
|
|
|
}/*
|
|
namespace ZNsInterface*/
|
|
|
|
|
|
namespace ZNsIDelgt
|
|
{
|
|
// class ZIDelgtMSG 를 상속하여 추가 멤버함수를 가진
|
|
// 인터페이스를 구현하는 클래스일 경우에는 여기에 둔다.
|
|
}/*
|
|
namespace ZNsIDelgt*/
|
|
|
|
|
|
class ZCAllocator
|
|
{
|
|
public:
|
|
static void* operator new (size_t AL_AllocSize ){return ::malloc(AL_AllocSize);}
|
|
static void* operator new[](size_t AL_AllocSize ){return ::malloc(AL_AllocSize);}
|
|
static void* operator new (size_t AL_AllocSize, void* AP_AllocBegin){return AP_AllocBegin ;}
|
|
static void* operator new[](size_t AL_AllocSize, void* AP_AllocBegin){return AP_AllocBegin ;}
|
|
|
|
static void operator delete (void* AP_Void){if(AP_Void!=0) ::free(AP_Void);}
|
|
static void operator delete[](void* AP_Void){if(AP_Void!=0) ::free(AP_Void);}
|
|
public:
|
|
};/*
|
|
class ZCAllocator*/
|
|
|
|
|
|
/*/////////////////////////////////////////////////////////////////
|
|
|
|
■ class ZCAllocator 는 정적 멤버를 사용하지만
|
|
class ZtCAllocClass<> 는 비정적 멤버를 사용한다.
|
|
|
|
■ 기본메모리 할당자로 ZtCAllocClass<> 을 사용하는 클래스가 나중에
|
|
다른 할당 알고리즘을 사용하고 싶을 때는 ZtCAllocClass<> 템플릿을
|
|
해당 Type 으로 전문화시켜주면 된다.
|
|
|
|
/////////////////////////////////////////////////////////////////*/
|
|
|
|
template<typename TType> class ZtCAllocClass :
|
|
public ZCAllocator
|
|
//////////////////////////////////////////////
|
|
{
|
|
public:
|
|
TType* NewMem (size_t AL_AllocSize){return (TType*)::malloc(AL_AllocSize) ;}
|
|
TType* NewArrMem(size_t AL_AllocSize){return (TType*)::malloc(AL_AllocSize*sizeof(TType));}
|
|
public:
|
|
void DeleteMem(void* AP_Void){if(AP_Void!=0) ::free(AP_Void);}
|
|
public:
|
|
};/*
|
|
template<typename TType> class ZtCAllocClass*/
|
|
|
|
|
|
class ZCAllocClass : public ZCAllocator
|
|
{
|
|
public:
|
|
void* NewMem (size_t AL_AllocSize){return ::malloc(AL_AllocSize) ;}
|
|
void DeleteMem(void* AP_Void ){if(AP_Void!=0) ::free(AP_Void);}
|
|
public:
|
|
};/*
|
|
class ZCAllocClass : public ZCAllocator*/
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////
|
|
|
|
■ 가끔 템플릿으로 클래스 설계를 하다보면 템플릿의 parameter 가
|
|
포인터나 참조일 경우, 무엇의 포인터나 참조형인지 알고 싶을 때
|
|
가 있다. 이런 경우에 ZtCTypeData<> 를 사용한다.
|
|
|
|
cf)
|
|
|
|
cout<<typeid(std::ZtCTypeData<ZTypIntI >::TypeData).name()<<endl;
|
|
cout<<typeid(std::ZtCTypeData<ZTypIntI*>::TypeData).name()<<endl;
|
|
cout<<typeid(std::ZtCTypeData<ZTypIntI&>::TypeData).name()<<endl;
|
|
|
|
-- 2010-01-15 00:11:00
|
|
|
|
■ ZtCTypeData<>::GetObjRef(~) 는 아래처럼 주로 포인터 자료형을
|
|
(null 이 아닌 경우) 항상 참조형으로 다루고 싶을 때 사용한다.
|
|
템플릿 Parameter 가 포인터형인데, 무엇의 포인터 형인지 알아
|
|
내어, 참조형으로 만들어 다른 함수의 인수로 사용하거나, 해당
|
|
멤버의 호출을 포인터 참조 표기 -> 말고 참조 표기(.)로 하면 편
|
|
할 것이다.
|
|
|
|
typedef std::CStringBase_T<char> CStringData ;
|
|
typedef CStringData* CStringDataPtr;
|
|
|
|
CStringData VO_CStringData("My");
|
|
CStringDataPtr VP_CStringData=&VO_CStringData;
|
|
|
|
(*VP_CStringData)("Data");
|
|
|
|
cout<<ZtCTypeData<CStringDataPtr>::GetObjRef(VP_CStringData)<<endl;
|
|
|
|
■ --
|
|
|
|
//////////////////////////////////////////////////////////////*/
|
|
|
|
typedef void (*ZfpNone)(void*); void ZfNone(void* AP_Void=0){};
|
|
|
|
template<typename TType> class ZtCTypeData
|
|
{ public: typedef TType TypeData;
|
|
static TType& GetObjRef(TType& AR_Type){return AR_Type ;}};
|
|
template<typename TType> class ZtCTypeData<TType*>
|
|
{ public: typedef TType TypeData;
|
|
static TType& GetObjRef(TType* AP_Type){return *AP_Type;}};
|
|
template<typename TType> class ZtCTypeData<TType&>
|
|
{ public: typedef TType TypeData;
|
|
static TType& GetObjRef(TType& AR_Type){return AR_Type ;}};
|
|
template< /*########*/ > class ZtCTypeData<void* >
|
|
{ public: typedef ZfpNone TypeData;
|
|
static ZfpNone GetObjRef(void* AP_Void){return ZfNone ;}};
|
|
|
|
template<typename TType> class ZtCTD
|
|
{ public: typedef TType TypeData;
|
|
static TType& GetObjRef(TType& AR_Type){return AR_Type ;}
|
|
static TType& GOR (TType& AR_Type){return AR_Type ;}};
|
|
template<typename TType> class ZtCTD<TType*>
|
|
{ public: typedef TType TypeData;
|
|
static TType& GetObjRef(TType* AP_Type){return *AP_Type;}
|
|
static TType& GOR (TType* AP_Type){return *AP_Type;}};
|
|
template<typename TType> class ZtCTD<TType&>
|
|
{ public: typedef TType TypeData;
|
|
static TType& GetObjRef(TType& AR_Type){return AR_Type ;}
|
|
static TType& GOR (TType& AR_Type){return AR_Type ;}};
|
|
template< /*########*/ > class ZtCTD<void* >
|
|
{ public: typedef ZfpNone TypeData;
|
|
static ZfpNone GetObjRef(void* AP_Void){return ZfNone ;}
|
|
static ZfpNone GOR (void* AP_Void){return ZfNone ;}};
|
|
|
|
|
|
/*////////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ 문자열 클래스에서 새로 메모리를 증가시켜야 할 때, 필요한 메모리보다 약간 더 할
|
|
당하는 것이 좋을 경우가 있는데, 이 경우에 필요한 메모리보다 어느 정도 만큼의 메
|
|
모리를 할당한 것인지를 지정한다.
|
|
|
|
////////////////////////////////////////////////////////////////////////////////*/
|
|
|
|
template<typename TTypeCh> class ZtCAllocMemSize
|
|
{
|
|
public:
|
|
|
|
template<typename TTypeSize> static TTypeSize
|
|
GetNewAllocSize(TTypeSize AL_NowAllocSize, TTypeSize AL_AllAllocSize )
|
|
{
|
|
/* AL_AllAllocSize : 해당 문자열 object 가 할당받은 문자 총갯수.
|
|
AL_NowAllocSize : AL_AllAllocSize 에서 현재 유효한 문자 갯수. */
|
|
|
|
return AL_NowAllocSize<=AL_AllAllocSize ? AL_NowAllocSize : AL_NowAllocSize*2 ;
|
|
}/*
|
|
template<typenanme TTypeSize> static TTypeSize
|
|
GetNewAllocSize(TTypeSize AL_NowAllocSize, TTypeSize AL_AllAllocSize ) */
|
|
|
|
public:
|
|
};/*
|
|
template<typename TTypeCh> class ZtCAllocMemSize */
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////
|
|
|
|
■ 아래 템플릿은 양방향 리스트에서 n 번째 원소에 접근할 때, 앞에
|
|
서부터 접근하는 것이 빠를지, 뒤에서부터 접근하는 것이 빠를지
|
|
판단할 때 사용한다.
|
|
|
|
//////////////////////////////////////////////////////////////*/
|
|
|
|
template<typename TTypSize> class ZtCShortCut
|
|
{
|
|
private:
|
|
|
|
static inline TTypSize GetAbs(TTypSize AI_Param) // 인수의 절대값을 얻는다.
|
|
{
|
|
return (AI_Param<0 ? -AI_Param : AI_Param);
|
|
}/*
|
|
static inline TTypSize GetAbs(TTypSize AI_Param)*/
|
|
/*
|
|
private:*/
|
|
public :
|
|
|
|
static ZTypIntI GetAbsMinOrder(TTypSize AI_One, TTypSize AI_Two, TTypSize AI_Three)
|
|
{
|
|
// 세 개의 인수 중에서 절대값이 최소가 되는 수는
|
|
// 몇 번째 인지 그 순서를 반환한다.
|
|
// 맨 앞의 인수가 절대값이 최소면 1 을 반환한다.
|
|
// 두 번째 인수의 절대값이 최소면 2 를 반환한다.
|
|
// 세 번째 인수의 절대값이 최소면 3 을 반환한다.
|
|
|
|
// 이 함수는 양방향 원형 연결리스트에서 n 번째 링크를 찾는데 쓰인다.
|
|
|
|
return ( GetAbs(AI_One)<=GetAbs(AI_Two ) /******/ ?
|
|
(GetAbs(AI_One)<=GetAbs(AI_Three) ? 1 : 3) :
|
|
(GetAbs(AI_Two)<=GetAbs(AI_Three) ? 2 : 3)
|
|
/****/ );
|
|
};/*
|
|
static ZTypIntI GetAbsMinOrder(TTypSize AI_One,TTypSize AI_Two, TTypSize AI_Three)*/
|
|
|
|
public:
|
|
};/*
|
|
template<typename TTypSize> class ZtCShortCut*/
|
|
|
|
|
|
#ifdef _WIN
|
|
|
|
using ::GetLastError;
|
|
|
|
|
|
inline ZTypIntI ZfGetLastError(){ return ::GetLastError(); }
|
|
|
|
|
|
template<typename TString> static bool
|
|
ZftGetLastErrMSG(TString& ARR_BuffCStr, ZTypIntI AI_ErrNo=0)
|
|
{
|
|
LPVOID VP_MsgBuff=0; DWORD ViErrNo =
|
|
(AI_ErrNo==0 ? ::GetLastError() : AI_ErrNo);
|
|
|
|
const DWORD CI_RetCode = ::FormatMessage( ///////////////
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_IGNORE_INSERTS ,
|
|
NULL ,
|
|
ViErrNo ,
|
|
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
|
|
(LPTSTR)&VP_MsgBuff,0,NULL
|
|
/*//////////*/ ); ///////////////////////////////////////
|
|
|
|
if(CI_RetCode==0) return false;
|
|
|
|
(ARR_BuffCStr=
|
|
((LPCTSTR)VP_MsgBuff))(", ErrNo=")(ViErrNo);
|
|
|
|
::LocalFree(VP_MsgBuff); return true;
|
|
}/*
|
|
template<typename TString> static bool
|
|
ZftGetLastErrMSG(TString& ARR_BuffCStr, ZTypIntI AI_ErrNo=0) */
|
|
|
|
// defined(_WIN)
|
|
#elif defined(__unix__)
|
|
|
|
inline ZTypIntI GetLastError(){return errno ;} // for compatibility with windows
|
|
inline ZTypIntI ZfGetLastError()
|
|
{
|
|
return errno ; // ::error 로 하면 안된다.
|
|
}/*
|
|
inline ZTypIntI ZfGetLastError()*/
|
|
|
|
template<typename TString> static bool
|
|
ZftGetLastErrMSG(TString& ARR_BuffCStr, ZTypIntI AI_ErrNo=0)
|
|
{
|
|
if(AI_ErrNo==0)
|
|
ARR_BuffCStr = ::strerror(errno );
|
|
else ARR_BuffCStr = ::strerror(AI_ErrNo);
|
|
|
|
return true; // for compatibility with window
|
|
}/*
|
|
template<typename TString> static bool
|
|
ZftGetLastErrMSG(TString& ARR_BuffCStr, ZTypIntI AI_ErrNo=0) */
|
|
|
|
//#elif defined(__unix__)
|
|
#else
|
|
|
|
inline ZTypIntI ZfGetLastError(){return errno ;}
|
|
|
|
template<typename TString> static bool
|
|
ZftGetLastErrMSG(TString& ARR_BuffCStr, ZTypIntI AI_ErrNo=0)
|
|
{
|
|
if(AI_ErrNo==0)
|
|
ARR_BuffCStr = ::strerror(errno );
|
|
else ARR_BuffCStr = ::strerror(AI_ErrNo);
|
|
|
|
return true; // for compatibility with window
|
|
}/*
|
|
template<typename TString> static bool
|
|
ZftGetLastErrMSG(TString& ARR_BuffCStr, ZTypIntI AI_ErrNo=0) */
|
|
|
|
#endif
|
|
|
|
|
|
// 절대값을 가져온다.
|
|
|
|
template<typename TLong> TLong ABS(TLong AL_Value)
|
|
{
|
|
if(AL_Value<0) return -AL_Value; return AL_Value;
|
|
}/*
|
|
template<typename TLong> TLong ABS(TLong AL_Value) */
|
|
|
|
template<typename TypeInt>
|
|
TypeInt AToInt(const char* ApcChar, ZTypIntI AI_Length)
|
|
{
|
|
if(AI_Length<1) return 0;
|
|
|
|
while(AI_Length>0 && ApcChar[AI_Length-1]==' ')
|
|
--AI_Length; // 뒤에 있는 공백을 제외.
|
|
//while
|
|
|
|
if(AI_Length<1) return 0;
|
|
|
|
const char* VPC_Char =ApcChar+AI_Length-1;
|
|
TypeInt VL_Temp;
|
|
TypeInt VL_Result =(*VPC_Char--)-'0';
|
|
TypeInt VL_Multiple=1;
|
|
|
|
while(--AI_Length>0)
|
|
{
|
|
if((VL_Temp=*VPC_Char--)<'0' || VL_Temp>'9' ) return 0;
|
|
|
|
VL_Result += (VL_Multiple*=10)*(VL_Temp-'0') ; ////////
|
|
}/*
|
|
while(--AI_Length>0)*/
|
|
|
|
return VL_Result;
|
|
}/*
|
|
template<typename TypeInt>
|
|
TypeInt AToInt(const char* ApcChar, ZTypIntI AI_Length) */
|
|
|
|
#ifdef _WIN
|
|
|
|
inline ZTypLLong ATOLL(const char* ApcChar)
|
|
{
|
|
if(ApcChar==0) return 0; return ::_atoi64(ApcChar);
|
|
}/*
|
|
inline ZTypLLong ATOLL(const char* ApcChar)*/
|
|
|
|
#else // !defined(_WIN)
|
|
|
|
inline ZTypLLong ATOLL(const char* ApcChar)
|
|
{
|
|
if(ApcChar==0) return 0; return ::atoll(ApcChar);
|
|
}/*
|
|
inline ZTypLLong ATOLL(const char* ApcChar)*/
|
|
|
|
#endif // !defined(_WIN)
|
|
|
|
|
|
inline ZTypLLong ATOLL(const char* ApcChar, ZTypIntI AI_Length)
|
|
{
|
|
return AToInt<ZTypLLong>(ApcChar, AI_Length);
|
|
}/*
|
|
inline ZTypLLong ATOL(const char* ApcChar, ZTypIntI AI_Length)*/
|
|
|
|
|
|
inline ZTypLong ATOL(const char* ApcChar)
|
|
{
|
|
if(ApcChar==0) return 0; return atol(ApcChar);
|
|
}/*
|
|
inline ZTypLong ATOL(const char* ApcChar)*/
|
|
|
|
inline ZTypLong ATOL(const char* ApcChar, ZTypIntI AI_Length)
|
|
{
|
|
return AToInt<ZTypLong>(ApcChar, AI_Length);
|
|
}/*
|
|
inline ZTypLong ATOL(const char* ApcChar, ZTypIntI AI_Length)*/
|
|
|
|
|
|
inline ZTypIntI ATOI(const char* ApcChar)
|
|
{
|
|
if(ApcChar==0) return 0; return atoi(ApcChar);
|
|
}/*
|
|
inline ZTypIntI ATOI(const char* ApcChar)*/
|
|
|
|
inline ZTypIntI ATOI(const char* ApcChar, ZTypIntI AI_Length)
|
|
{
|
|
return AToInt<ZTypIntI>(ApcChar, AI_Length);
|
|
}/*
|
|
inline ZTypIntI ATOI(const char* ApcChar, ZTypIntI AI_Length)*/
|
|
|
|
inline double ATOD(const char* ApcChar)
|
|
{
|
|
return ApcChar==0 ? 0 : ::atof(ApcChar) ;
|
|
}/*
|
|
inline double ATOD(const char* ApcChar)*/
|
|
|
|
|
|
template<typename TTypeCh>
|
|
inline ZTypLength ZftGetLength(const TTypeCh* ApcChar)
|
|
{
|
|
if(ApcChar==0) return 0;
|
|
|
|
ZTypLength VL_Length=0 ;
|
|
|
|
while(*(ApcChar+VL_Length)!=_T('\0'))
|
|
++VL_Length;
|
|
/////////////////////////////////////
|
|
|
|
return VL_Length;
|
|
}/*
|
|
template<typename TTypeCh>
|
|
inline ZTypLength ZftGetLength(const TTypeCh* ApcChar) */
|
|
|
|
|
|
template<typename TTypeSize, typename TTypeCh>
|
|
inline TTypeSize ZftGetLengthType(const TTypeCh* ApcChar)
|
|
{
|
|
if(ApcChar==0) return 0;
|
|
|
|
TTypeSize VL_Length=0 ;
|
|
|
|
while(*(ApcChar+VL_Length)!=_T('\0'))
|
|
++VL_Length;
|
|
/////////////////////////////////////
|
|
|
|
return VL_Length;
|
|
}/*
|
|
template<typename TTypeSize, typename TTypeCh>
|
|
inline TTypeSize ZftGetLengthType(const TTypeCh* ApcChar) */
|
|
|
|
|
|
template<typename TTypeCh>
|
|
inline ZTypLength ZftLength(const TTypeCh* ApcChar)
|
|
{
|
|
return ZftGetLength(ApcChar);
|
|
}/*
|
|
template<typename TTypeCh>
|
|
inline ZTypLength ZftLength(const TTypeCh* ApcChar) */
|
|
|
|
template<typename TTypeSize, typename TTypeCh>
|
|
inline TTypeSize ZfLengthType(const TTypeCh* ApcChar)
|
|
{
|
|
return ZftGetLengthType<TTypeSize, TTypeCh>(ApcChar);
|
|
}/*
|
|
template<typename TTypeSize, typename TTypeCh>
|
|
inline TTypeSize ZftLengthType(const TTypeCh* ApcChar) */
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ ZftCopyChars() 함수는 최대 AL_DestSize 만큼 복사하는데, ZNsWin.H 의 CRegistry 클래스
|
|
에서 Windows 의 Strsafe.h 에 정의된 StringCchCopy() 을 대신하려고 만들었다. mingw 에
|
|
서는 헤더 파일 Strsafe.h 이 없는 경우가 있는 것이다. 원래 StringCchCopy() 선언은 이렇다.
|
|
|
|
HRESULT StringCchCopy(
|
|
__out LPTSTR pszDest,
|
|
__in size_t cchDest,
|
|
__in LPCTSTR pszSrc
|
|
);
|
|
|
|
This function can return one of the following values. It is strongly recommended
|
|
that you use the SUCCEEDED and FAILED macros to test the return value of this function.
|
|
|
|
Return code
|
|
|
|
S_OK : Source data was present, fully copied without truncation, and the resultant
|
|
destination buffer is null-terminated.
|
|
|
|
STRSAFE_E_INVALID_PARAMETER : The value in cchDest is either 0 or larger than STRSAFE_MAX_CCH.
|
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER : The copy operation failed due to insufficient buffer
|
|
space. The destination buffer contains a truncated, null-terminated version of the
|
|
intended result. In situations where truncation is acceptable, this may not necessarily
|
|
be seen as a failure condition.
|
|
|
|
-- 2012-08-15 07:40:00
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////*/
|
|
|
|
template<typename TTypeCh, typename TTypeSize> TTypeSize
|
|
ZftCopyChars(TTypeCh* ApcDest, TTypeSize AL_DestSize, const TTypeCh* ApcSource)
|
|
{
|
|
/* ApcSource must be null-terminated. AL_DestSize
|
|
must be equal to or more than strlen(ApcSource)+1.
|
|
|
|
Null 문자를 포함하여 ApcDest 에 복사된 길이를 리턴한다. */
|
|
|
|
if(ApcSource==0) return 0;
|
|
|
|
TTypeSize VL_SourceSize=0 ;
|
|
TTypeCh* VPC_Dest =ApcDest ;
|
|
const TTypeCh* VPC_Source =ApcSource;
|
|
|
|
for(; VL_SourceSize<AL_DestSize; ++VL_SourceSize)
|
|
{
|
|
if(*ApcSource==0)
|
|
{
|
|
if(VL_SourceSize<AL_DestSize+1)
|
|
{ *VPC_Dest=0; return VL_SourceSize+1; }
|
|
|
|
return VL_SourceSize;
|
|
}/*
|
|
if(*ApcSource==0)*/
|
|
|
|
*VPC_Dest = *VPC_Source;
|
|
}/*
|
|
for(; VL_SourceSize<AL_DestSize; ++VL_SourceSize)*/
|
|
}/*
|
|
template<typename TTypeCh, typename TTypeSize> TTypeSize
|
|
ZftCopyChars(TTypeCh* ApcDest, TTypeSize AL_DestSize, const TTypeCh* ApcSource) */
|
|
|
|
|
|
template<typename TType> class ZtCInit
|
|
{
|
|
public:
|
|
void operator()(TType& AR_TypeArg){}
|
|
public:
|
|
void OnInit(TType& AR_TypeArg){}
|
|
void OnFini(TType& AR_TypeArg){}
|
|
public:
|
|
};/*
|
|
template<typename TType> class ZtCInit*/
|
|
|
|
|
|
class ZCInit
|
|
{
|
|
public:
|
|
template<typename TType> void operator()(TType& AR_TypeArg){}
|
|
template<typename TType> void OnInit (TType& AR_TypeArg){}
|
|
template<typename TType> void OnFini (TType& AR_TypeArg){}
|
|
|
|
void OnInit(){}
|
|
void OnFini(){}
|
|
public:
|
|
};/*
|
|
class ZCInit*/
|
|
|
|
|
|
class ZCExceptBase
|
|
{
|
|
public: void* operator()(){return 0;}
|
|
};/*
|
|
class ZCExceptBase*/
|
|
|
|
|
|
// 예외 기반 클래스를 template 로 하면 여러 기법을 사용할 수 있다.
|
|
|
|
template< typename TType, typename TypeArg=const TType&
|
|
>
|
|
class ZtCExceptBase_T /*///////////////////////////////*/
|
|
{
|
|
protected:
|
|
TType mo_Type;
|
|
public :
|
|
|
|
ZtCExceptBase_T(){}
|
|
|
|
ZtCExceptBase_T(TypeArg TypeArgObj):mo_Type(TypeArgObj){}
|
|
|
|
TType& operator()(){return mo_Type;}
|
|
|
|
public :
|
|
};/*
|
|
template< typename TType, typename TypeArg=const TType&
|
|
>
|
|
class ZtCExceptBase_T /////////////////////////////////*/
|
|
|
|
|
|
/*/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ 이 클래스를 private 상속하는 클래스에서 복사생성자와 대입연산자의 사용을 막는다.
|
|
|
|
■ template class 나 class member template 을 사용할 때, 인수가 class object 이고
|
|
이 인수가 반드시 참조형으로 전달되어야하고, 복사 생성되어 전달될 수 없을때, 이를
|
|
보장하기 위해 해당 class 를 아래 class 로부터 상속할 필요가 있다.
|
|
|
|
이를 모르고 있다가, CAsyncServ_H 에 정의된 CAsyncServ_T<> 클래스를 사용할 때, 이
|
|
클래스가 작업쓰레드 풀 인수로 복사 생성되어 전달되는 것을 나중에 알고 깜짝 놀랬다.
|
|
|
|
-- 2010-12-20 23:51:00
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////*/
|
|
|
|
class CNonCopyable
|
|
{
|
|
private:
|
|
CNonCopyable(const CNonCopyable& rhs){}
|
|
CNonCopyable& operator=(const CNonCopyable& rhs){return *this;}
|
|
public :
|
|
CNonCopyable(){}
|
|
public :
|
|
};/*
|
|
class CNonCopyable*/
|
|
|
|
|
|
/*///////////////////////////////////////////////////////////////////////////
|
|
|
|
■ 리스트나 트리 구조에서 쓰는 링크의 힙-자유 기억 공간-을 구현하는 class 는
|
|
class ZCFreeAllocBase 를 상속한다. 이 자유 기억 공간 클래스의 object 는 힙
|
|
에 할당한다.
|
|
|
|
///////////////////////////////////////////////////////////////////////////*/
|
|
|
|
class ZCFreeAllocBase
|
|
{
|
|
public:
|
|
|
|
virtual ~ZCFreeAllocBase(){}
|
|
|
|
virtual long GetHeapSize() const{return 0;}
|
|
virtual long GetMemSize () const{return 0;}
|
|
|
|
const char* GetTypeName() const
|
|
{
|
|
return typeid(*this).name();
|
|
}/*
|
|
const char* GetTypeName() const*/
|
|
|
|
virtual void DeleteAllInHeap(){}
|
|
|
|
public:
|
|
};/*
|
|
class ZCFreeAllocBase*/
|
|
|
|
|
|
// 자유 기억 공간을 총괄하는 단방향 연결 리스트
|
|
|
|
class ZCHeapAllocList
|
|
{
|
|
public:
|
|
|
|
class ZCLink
|
|
{
|
|
public:
|
|
friend class ZCHeapAllocList;
|
|
public:
|
|
|
|
ZCLink(ZCFreeAllocBase& ArCFreeAllocBase):mr_AllocBase(ArCFreeAllocBase), mp_NextLink(0)
|
|
{
|
|
}/*
|
|
ZCLink(ZCFreeAllocBase& ArCFreeAllocBase)*/
|
|
|
|
ZCLink* GetNextLink()
|
|
{
|
|
return mp_NextLink;
|
|
}/*
|
|
ZCLink* GetNextLink()*/
|
|
|
|
ZCLink* GetNextLink(long AL_Distance)
|
|
{
|
|
ZCLink* VP_NowLink=this;
|
|
|
|
while(--AL_Distance>=0)
|
|
VP_NowLink=VP_NowLink->mp_NextLink;
|
|
|
|
return VP_NowLink;
|
|
}/*
|
|
ZCLink* GetNextLink(long AL_Distance)*/
|
|
|
|
ZCFreeAllocBase& GetData()
|
|
{
|
|
return mr_AllocBase;
|
|
}/*
|
|
ZCFreeAllocBase& GetData()*/
|
|
|
|
/*public :*/
|
|
|
|
private:
|
|
ZCFreeAllocBase& mr_AllocBase;
|
|
ZCLink* mp_NextLink ;
|
|
private:
|
|
};/*
|
|
class ZCLink*/
|
|
|
|
|
|
/*public :*/
|
|
private:
|
|
ZTypIntL ml_Size ;
|
|
ZCLink* mp_HeadLink ;
|
|
ZCLink* mp_TailLink ;
|
|
private:
|
|
|
|
void AddLink(ZCLink* AP_NewLink)
|
|
{
|
|
if(ml_Size++ == 0)
|
|
{
|
|
mp_HeadLink= mp_TailLink=AP_NewLink ;
|
|
mp_TailLink->mp_NextLink=mp_HeadLink;
|
|
}
|
|
else
|
|
{
|
|
mp_TailLink->mp_NextLink=AP_NewLink ;
|
|
AP_NewLink ->mp_NextLink=mp_HeadLink;
|
|
mp_TailLink=mp_TailLink->mp_NextLink;
|
|
}/*
|
|
else*/
|
|
}/*
|
|
void AddLink(ZCLink* AP_NewLink)*/
|
|
|
|
/*private:*/
|
|
public :
|
|
|
|
ZCHeapAllocList()
|
|
{
|
|
ml_Size =0;
|
|
mp_HeadLink =0;
|
|
mp_TailLink =0;
|
|
}/*
|
|
ZCHeapAllocList()*/
|
|
|
|
template<typename TypeFreeAlloc> TypeFreeAlloc& AddFreeAlloc()
|
|
{
|
|
// TypeFreeAlloc 은 ZCFreeAllocBase 의 파생클래스여야 한다.
|
|
|
|
TypeFreeAlloc* VP_TypeFreeAlloc=new TypeFreeAlloc;
|
|
|
|
ZCLink* VP_NewLink=new ZCLink(*VP_TypeFreeAlloc);
|
|
|
|
AddLink(VP_NewLink); return *VP_TypeFreeAlloc;
|
|
}/*
|
|
template<typename TypeFreeAlloc> TypeFreeAlloc& AddFreeAlloc() */
|
|
|
|
void AddFreeAllocBase(ZCFreeAllocBase& ArCFreeAllocBase)
|
|
{
|
|
AddLink( new ZCLink(ArCFreeAllocBase) );
|
|
}/*
|
|
void AddFreeAllocBase(ZCFreeAllocBase& ArCFreeAllocBase)*/
|
|
|
|
|
|
ZCFreeAllocBase& GetData(long AL_Index)
|
|
{
|
|
return mp_HeadLink->GetNextLink(AL_Index-1)->mr_AllocBase;
|
|
}/*
|
|
ZCFreeAllocBase& GetData(long AL_Index)*/
|
|
|
|
ZCLink* GetHeadLink()
|
|
{
|
|
return mp_HeadLink;
|
|
}/*
|
|
ZCLink* GetHeadLink()*/
|
|
|
|
template<typename DeriveType> DeriveType& GetDataType(long AL_Index)
|
|
{
|
|
return static_cast<DeriveType&>( mp_HeadLink->GetNextLink(AL_Index-1)->mr_AllocBase );
|
|
}/*
|
|
template<typename DeriveType> DeriveType& GetDataType(long AL_Index) */
|
|
|
|
void FreeAll()
|
|
{
|
|
ZCLink* VP_Link=mp_HeadLink;
|
|
|
|
for(long i=1; i<=ml_Size; ++i)
|
|
{
|
|
VP_Link->mr_AllocBase.DeleteAllInHeap();
|
|
VP_Link=VP_Link->mp_NextLink;
|
|
}/*
|
|
for(long i=1; i<=ml_Size; ++i)*/
|
|
}/*
|
|
void FreeAll()*/
|
|
|
|
void DeleteAll()
|
|
{
|
|
ZCLink* VP_CutLink=0;
|
|
|
|
for(long i=1; i<=ml_Size; ++i)
|
|
{
|
|
VP_CutLink =mp_HeadLink;
|
|
mp_HeadLink=mp_HeadLink->mp_NextLink;
|
|
|
|
delete VP_CutLink;
|
|
}/*
|
|
for(long i=1; i<=ml_Size; ++i)*/
|
|
|
|
ml_Size=0;
|
|
}/*
|
|
void DeleteAll()*/
|
|
|
|
void ClearAll()
|
|
{
|
|
ZCLink* VP_CutLink=0;
|
|
|
|
for(long i=1; i<=ml_Size; ++i)
|
|
{
|
|
VP_CutLink =mp_HeadLink ;
|
|
mp_HeadLink=mp_HeadLink->mp_NextLink;
|
|
|
|
VP_CutLink->
|
|
mr_AllocBase.DeleteAllInHeap() ;
|
|
|
|
delete VP_CutLink;
|
|
}/*
|
|
for(long i=1; i<=ml_Size; ++i)*/
|
|
|
|
ml_Size=0;
|
|
}/*
|
|
void ClearAll()*/
|
|
|
|
ZTypIntL GetSize() const
|
|
{
|
|
return ml_Size;
|
|
}/*
|
|
ZTypIntL GetSize() const*/
|
|
|
|
public:
|
|
};/*
|
|
class ZCHeapAllocList*/
|
|
|
|
|
|
static ZCHeapAllocList& GetCHeapAllocList()
|
|
{
|
|
static ZCHeapAllocList SO_CHeapAllocList; return SO_CHeapAllocList;
|
|
}/*
|
|
static ZCHeapAllocList& GetCHeapAllocList()*/
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////
|
|
|
|
■ 템플릿 인자를 정의할 때 참조로 하지 않은 경우에 object 의 크기가
|
|
크면 포인터로 넘겨야 하는데, 이러면 어느 object 의 포인터인지 알
|
|
수 있지만 그 object 에 속한 enum 형이나 typedef 선언 및 기타 자료
|
|
형은 알 수 없다. 그래서 object 의 포인터를 포장하는 클래스 템플릿
|
|
ZtCObjectPtr<> 을 설계한다.
|
|
|
|
■ typedef ZtCStringBase<char > CStringBase;
|
|
typedef ZtCObjectPtr <CStringBase> CObjectPtr ;
|
|
|
|
라는 선언이 있으면 CStringBase::TTypeChar 에 접근할 때에는
|
|
|
|
CObjectPtr::TypeData::TTypeChar 로 하면 된다.
|
|
|
|
■ 포인터 자료형에 대하여 ZtCObjectPtr<> 대신 더 간단하게
|
|
ZtCTypeData<> 를 사용해도 된다. 이 편이 오히려 낳을 것 같다.
|
|
|
|
-- 2010-01-24 22:25:00
|
|
|
|
//////////////////////////////////////////////////////////////////*/
|
|
|
|
template<typename TType> class ZtCObjectPtr
|
|
{
|
|
public :
|
|
typedef TType TypeData;
|
|
protected:
|
|
TType& mr_TypeData;
|
|
public :
|
|
|
|
ZtCObjectPtr(TType& ArCData):mr_TypeData(ArCData){}
|
|
|
|
TType* operator->(){return &mr_TypeData;}
|
|
TType& operator* (){return mr_TypeData;}
|
|
operator TType& (){return mr_TypeData;}
|
|
|
|
public :
|
|
};/*
|
|
template<typename TType> class ZtCObjectPtr */
|
|
|
|
|
|
/*/////////////////////////////////////////////////////////
|
|
|
|
■ object 를 heap 에 생성하고, 참조 카운트를 이용하여 관리.
|
|
|
|
-- 2014-07-20 04:49:00
|
|
|
|
/////////////////////////////////////////////////////////*/
|
|
|
|
template< typename TType, typename TAllocClass=ZCAllocClass
|
|
>
|
|
class ZtCObjectNew : public TAllocClass ////////////////////
|
|
{
|
|
public :
|
|
typedef TType TypeData ;
|
|
typedef TAllocClass ZCAllocator;
|
|
private:
|
|
|
|
struct StTypeRefCnt
|
|
{
|
|
TType MO_TypeData;
|
|
ZTypInt MI_RefCount;
|
|
|
|
StTypeRefCnt(){MI_RefCount=0;}
|
|
};/*
|
|
struct StTypeRefCnt*/
|
|
|
|
private:
|
|
StTypeRefCnt* mp_StTypeRefCnt;
|
|
public :
|
|
|
|
ZtCObjectNew()
|
|
{
|
|
mp_StTypeRefCnt = (StTypeRefCnt*)
|
|
this->ZCAllocator::NewMem( sizeof(StTypeRefCnt) );
|
|
mp_StTypeRefCnt->MI_RefCount = 1 ;
|
|
|
|
new(&mp_StTypeRefCnt->MO_TypeData) TypeData;
|
|
}/*
|
|
ZtCObjectNew()*/
|
|
|
|
ZtCObjectNew(const TypeData& AR_TypeData)
|
|
{
|
|
mp_StTypeRefCnt = (StTypeRefCnt*)
|
|
this->ZCAllocator::NewMem( sizeof(StTypeRefCnt) );
|
|
mp_StTypeRefCnt->MI_RefCount = 1 ;
|
|
|
|
new(&mp_StTypeRefCnt->MO_TypeData) TypeData(AR_TypeData);
|
|
}/*
|
|
ZtCObjectNew(const TypeData& AR_TypeData)*/
|
|
|
|
template<typename TTypeArg1, typename TTypeArg2>
|
|
ZtCObjectNew(TTypeArg1& ArTTypeArg1, TTypeArg2& ArTTypeArg2)
|
|
{
|
|
mp_StTypeRefCnt = (StTypeRefCnt*)
|
|
this->ZCAllocator::NewMem(sizeof(StTypeRefCnt));
|
|
mp_StTypeRefCnt->MI_RefCount = 1 ;
|
|
|
|
new(&mp_StTypeRefCnt->MO_TypeData)
|
|
TypeData(ArTTypeArg1, ArTTypeArg2);
|
|
}/*
|
|
template<typename TTypeArg1, typename TTypeArg2>
|
|
ZtCObjectNew(TTypeArg1& ArTTypeArg1, TTypeArg2& ArTTypeArg2))*/
|
|
|
|
ZtCObjectNew(const ZtCObjectNew& rhs)
|
|
{
|
|
mp_StTypeRefCnt=rhs.mp_StTypeRefCnt; ++mp_StTypeRefCnt->MI_RefCount;
|
|
}/*
|
|
ZtCObjectNew(const ZtCObjectNew& rhs)*/
|
|
|
|
~ZtCObjectNew()
|
|
{
|
|
if(--mp_StTypeRefCnt->MI_RefCount<=0) this->ZCAllocator::DeleteMem(mp_StTypeRefCnt);
|
|
}/*
|
|
~ZtCObjectNew()*/
|
|
|
|
ZtCObjectNew& operator=(const ZtCObjectNew& rhs)
|
|
{
|
|
if(this==&rhs || mp_StTypeRefCnt==rhs.mp_StTypeRefCnt) return *this;
|
|
|
|
#if(0)
|
|
mp_StTypeRefCnt->MO_TypeData = rhs.mp_StTypeRefCnt->MO_TypeData; return *this;
|
|
#else
|
|
if(--mp_StTypeRefCnt->MI_RefCount<=0) this->ZCAllocator::DeleteMem(mp_StTypeRefCnt);
|
|
|
|
mp_StTypeRefCnt = rhs.mp_StTypeRefCnt; ++mp_StTypeRefCnt->MI_RefCount; return *this;
|
|
#endif
|
|
}/*
|
|
ZtCObjectNew& operator=(const ZtCObjectNew& rhs)*/
|
|
|
|
ZtCObjectNew& operator=(const TypeData& AR_TypeData)
|
|
{
|
|
if(&mp_StTypeRefCnt->MO_TypeData==&AR_TypeData) return *this;
|
|
|
|
mp_StTypeRefCnt->MO_TypeData = AR_TypeData; return *this;
|
|
}/*
|
|
ZtCObjectNew& operator=(const TypeData& AR_TypeData)*/
|
|
|
|
TypeData& operator* (){return mp_StTypeRefCnt->MO_TypeData;}
|
|
TypeData* operator->(){return &mp_StTypeRefCnt->MO_TypeData;}
|
|
|
|
operator TypeData& (){return mp_StTypeRefCnt->MO_TypeData;}
|
|
|
|
ZTypInt GetRefCnt() const{return mp_StTypeRefCnt->MI_RefCount;}
|
|
TypeData* GetObjPtr() const{return &mp_StTypeRefCnt->MO_TypeData;}
|
|
|
|
public :
|
|
};/*
|
|
template< typename TType, typename TAllocClass=ZCAllocClass
|
|
>
|
|
class ZtCObjectNew : public TAllocClass //////////////////*/
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
/*/////////////////////////////////////////////////////////////////////
|
|
|
|
■ 멀티쓰레드 환경에서는 반드시 _REENTRANT 이 정의되어 있어야 한다. 이
|
|
것을 체크하기 위해 쓰레드를 만드는 클래스가 있다면 생성자에서 아래
|
|
함수를 호출해서 _REENTRANT 가 정의되어 있는지 확인한다.
|
|
|
|
-- 2009-12-23 10:38:00
|
|
|
|
/////////////////////////////////////////////////////////////////////*/
|
|
|
|
inline void _DEBUG_REENTRANT_Check()
|
|
{
|
|
if(_REENTRANT_BOOL_<1)
|
|
{
|
|
std::fstream fileout("DEBUG.txt", std::ios::out | std::ios::app);
|
|
|
|
fileout<<"◆◆ Error! : _REENTRANT is Not Defined In Multi-Thread"<<std::endl;
|
|
fileout.close();
|
|
|
|
::exit(1);
|
|
}/*
|
|
if(_REENTRANT_BOOL_<1)*/
|
|
}/*
|
|
inline void _DEBUG_REENTRANT_Check()*/
|
|
|
|
#define _DEBUG_REENTRANT_CHECK_ _DEBUG_REENTRANT_Check();
|
|
|
|
#else // !defined(_DEBUG)
|
|
|
|
#define _DEBUG_REENTRANT_CHECK_
|
|
|
|
#endif // !defined(_DEBUG)
|
|
|
|
|
|
#if defined(_REENTRANT)
|
|
|
|
|
|
class ZCExceptSmallLock : public ZCExceptBase
|
|
{
|
|
private:
|
|
long ml_ErrCode;
|
|
string mo_ErrMSG ;
|
|
public :
|
|
|
|
ZCExceptSmallLock(long AL_ErrCode, const char* AP_ErrMSG)
|
|
{
|
|
ml_ErrCode=AL_ErrCode; //////////////
|
|
|
|
if(AP_ErrMSG!=0) mo_ErrMSG=AP_ErrMSG;
|
|
}/*
|
|
ZCExceptSmallLock(long AL_ErrCode, const char* AP_ErrMSG)*/
|
|
|
|
long GetErrCode() const{return ml_ErrCode;}
|
|
const string& GetErrMSG () const{return mo_ErrMSG ;}
|
|
|
|
public:
|
|
};/*
|
|
class ZCExceptSmallLock : public ZCExceptBase*/
|
|
|
|
|
|
#endif //defined(_REENTRANT)
|
|
|
|
|
|
#if defined(_REENTRANT) && defined(_WIN)
|
|
|
|
|
|
/*//////////////////////////////////////////////////////
|
|
|
|
■ 아래 클래스는 여러 자료구조에서 내부적으로 정적변수나
|
|
정적 object 를 동기화하기 위해 사용한다.
|
|
|
|
윈도우에서는 크리티컬 섹션을 쓰는 것이 좋으나
|
|
|
|
BOOL TryEnterCriticalSection(LPCRITICAL_SECTION)
|
|
|
|
함수가 제대로 지원되지 않고 있다.
|
|
|
|
//////////////////////////////////////////////////////*/
|
|
|
|
|
|
class ZCMutexSmallLock;
|
|
|
|
|
|
class ZCMutexSmallInit
|
|
{
|
|
private:
|
|
HANDLE mh_Mutex;
|
|
public :
|
|
|
|
void Lock() throw(ZCExceptSmallLock&)
|
|
{
|
|
long VL_ErrCode=0;
|
|
|
|
if((VL_ErrCode = ::WaitForSingleObject(mh_Mutex, INFINITE))==WAIT_ABANDONED)
|
|
{
|
|
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::Lock()");
|
|
}/*
|
|
if((VL_ErrCode = ::WaitForSingleObject(mh_Mutex, INFINITE))==WAIT_ABANDONED)*/
|
|
}/*
|
|
void Lock() throw(ZCExceptSmallLock&)*/
|
|
|
|
void UnLock()
|
|
{
|
|
::ReleaseMutex(mh_Mutex);
|
|
}/*
|
|
void UnLock()*/
|
|
|
|
ZCMutexSmallInit()
|
|
{
|
|
/* MUTEX 를 신호 상태로 만들고 이 함수를 호출한 쓰레드가 MUTEX 를 소유하지 않게
|
|
한다. 신호 상태라 함은 다른 쓰레드가 진입할 수 있는 상태를 말한다. */
|
|
|
|
mh_Mutex = ::CreateMutex(NULL, FALSE, NULL);
|
|
}/*
|
|
ZCMutexSmallInit()*/
|
|
|
|
~ZCMutexSmallInit()
|
|
{
|
|
::CloseHandle(mh_Mutex);
|
|
}/*
|
|
~ZCMutexSmallInit()*/
|
|
|
|
public:
|
|
};/*
|
|
class ZCMutexSmallInit*/
|
|
|
|
|
|
class ZCMutexSmallLock
|
|
{
|
|
private:
|
|
ZCMutexSmallInit& mr_ZCMutexInit;
|
|
public :
|
|
|
|
ZCMutexSmallLock(ZCMutexSmallInit& ArZCMutexInit):mr_ZCMutexInit(ArZCMutexInit)
|
|
{
|
|
mr_ZCMutexInit.Lock();
|
|
}/*
|
|
ZCMutexSmallLock(ZCMutexSmallInit& ArZCMutexInit)*/
|
|
|
|
~ZCMutexSmallLock()
|
|
{
|
|
mr_ZCMutexInit.UnLock();
|
|
}/*
|
|
~ZCMutexSmallLock()*/
|
|
|
|
public:
|
|
};/*
|
|
class ZCMutexSmallLock*/
|
|
|
|
|
|
|
|
#elif defined(_REENTRANT) && defined(__unix__)
|
|
|
|
|
|
// 유닉스(특히 리눅스) 상에서 _REENTRANT 이 정의되어 있으면
|
|
// -lpthread 옵션을 잊지 말 것.
|
|
|
|
|
|
class ZCMutexSmallLock;
|
|
|
|
|
|
class ZCMutexSmallInit
|
|
{
|
|
private:
|
|
::pthread_mutex_t mo_Mutex;
|
|
public :
|
|
|
|
void Lock() throw(ZCExceptSmallLock&)
|
|
{
|
|
long VL_ErrCode=0;
|
|
|
|
if((VL_ErrCode=::pthread_mutex_lock(&mo_Mutex))!=0)
|
|
{
|
|
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::Lock()");
|
|
}/*
|
|
if((VL_ErrCode=::pthread_mutex_lock(&mo_Mutex))!=0)*/
|
|
}/*
|
|
void Lock() throw(ZCExceptSmallLock&)*/
|
|
|
|
void UnLock() throw(ZCExceptSmallLock&)
|
|
{
|
|
long VL_ErrCode=0;
|
|
|
|
if((VL_ErrCode=::pthread_mutex_unlock(&mo_Mutex))!=0)
|
|
{
|
|
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::UnLock()");
|
|
}/*
|
|
if((VL_ErrCode=::pthread_mutex_unlock(&mo_Mutex))!=0)*/
|
|
}/*
|
|
void UnLock() throw(ZCExceptSmallLock&)*/
|
|
|
|
ZCMutexSmallInit() throw(ZCExceptSmallLock&)
|
|
{
|
|
::pthread_mutexattr_t VO_MutexAttr;
|
|
|
|
::pthread_mutexattr_init(&VO_MutexAttr);
|
|
::pthread_mutexattr_settype(&VO_MutexAttr, PTHREAD_MUTEX_RECURSIVE);
|
|
|
|
long VL_ErrCode=0;
|
|
|
|
if((VL_ErrCode=::pthread_mutex_init(&mo_Mutex, &VO_MutexAttr))!=0)
|
|
{
|
|
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::ZCMutexSmallInit()");
|
|
}/*
|
|
if((VL_ErrCode=::pthread_mutex_init(&mo_Mutex, &VO_MutexAttr))!=0)*/
|
|
}/*
|
|
ZCMutexSmallInit() throw(ZCExceptSmallLock&)*/
|
|
|
|
~ZCMutexSmallInit() throw(ZCExceptSmallLock&)
|
|
{
|
|
long VL_ErrCode=0;
|
|
|
|
if((VL_ErrCode=::pthread_mutex_destroy(&mo_Mutex))!=0)
|
|
{
|
|
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::~ZCMutexSmallInit()");
|
|
}/*
|
|
if((VL_ErrCode=::pthread_mutex_destroy(&mo_Mutex))!=0)*/
|
|
}/*
|
|
~ZCMutexSmallInit() throw(ZCExceptSmallLock&)*/
|
|
|
|
public:
|
|
};/*
|
|
class ZCMutexSmallInit*/
|
|
|
|
|
|
class ZCMutexSmallLock
|
|
{
|
|
private:
|
|
ZCMutexSmallInit& mr_ZCMutexInit;
|
|
public :
|
|
|
|
ZCMutexSmallLock(ZCMutexSmallInit& ArZCMutexInit):mr_ZCMutexInit(ArZCMutexInit)
|
|
{
|
|
mr_ZCMutexInit.Lock();
|
|
}/*
|
|
ZCMutexSmallLock(ZCMutexSmallInit& ArZCMutexInit)*/
|
|
|
|
~ZCMutexSmallLock()
|
|
{
|
|
mr_ZCMutexInit.UnLock();
|
|
}/*
|
|
~ZCMutexSmallLock()*/
|
|
|
|
public:
|
|
};/*
|
|
class ZCMutexSmallLock*/
|
|
|
|
|
|
// defined(_REENTRANT) && defined(__unix__)
|
|
#elif defined(_REENTRANT)
|
|
|
|
|
|
// _REENTRANT 이 정의되어 있으면 -lpthread 옵션을 잊지 말 것.
|
|
|
|
class ZCMutexSmallLock;
|
|
|
|
|
|
class ZCMutexSmallInit
|
|
{
|
|
private:
|
|
::pthread_mutex_t mo_Mutex;
|
|
public :
|
|
|
|
void Lock() throw(ZCExceptSmallLock&)
|
|
{
|
|
long VL_ErrCode=0;
|
|
|
|
if((VL_ErrCode=::pthread_mutex_lock(&mo_Mutex))!=0)
|
|
{
|
|
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::Lock()");
|
|
}/*
|
|
if((VL_ErrCode=::pthread_mutex_lock(&mo_Mutex))!=0)*/
|
|
}/*
|
|
void Lock() throw(ZCExceptSmallLock&)*/
|
|
|
|
void UnLock() throw(ZCExceptSmallLock&)
|
|
{
|
|
long VL_ErrCode=0;
|
|
|
|
if((VL_ErrCode=::pthread_mutex_unlock(&mo_Mutex))!=0)
|
|
{
|
|
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::UnLock()");
|
|
}/*
|
|
if((VL_ErrCode=::pthread_mutex_unlock(&mo_Mutex))!=0)*/
|
|
}/*
|
|
void UnLock() throw(ZCExceptSmallLock&)*/
|
|
|
|
ZCMutexSmallInit() throw(ZCExceptSmallLock&)
|
|
{
|
|
::pthread_mutexattr_t VO_MutexAttr;
|
|
|
|
::pthread_mutexattr_init(&VO_MutexAttr);
|
|
::pthread_mutexattr_settype(&VO_MutexAttr, PTHREAD_MUTEX_RECURSIVE);
|
|
|
|
long VL_ErrCode=0;
|
|
|
|
if((VL_ErrCode=::pthread_mutex_init(&mo_Mutex, &VO_MutexAttr))!=0)
|
|
{
|
|
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::ZCMutexSmallInit()");
|
|
}/*
|
|
if((VL_ErrCode=::pthread_mutex_init(&mo_Mutex, &VO_MutexAttr))!=0)*/
|
|
}/*
|
|
ZCMutexSmallInit() throw(ZCExceptSmallLock&)*/
|
|
|
|
~ZCMutexSmallInit() throw(ZCExceptSmallLock&)
|
|
{
|
|
long VL_ErrCode=0;
|
|
|
|
if((VL_ErrCode=::pthread_mutex_destroy(&mo_Mutex))!=0)
|
|
{
|
|
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::~ZCMutexSmallInit()");
|
|
}/*
|
|
if((VL_ErrCode=::pthread_mutex_destroy(&mo_Mutex))!=0)*/
|
|
}/*
|
|
~ZCMutexSmallInit() throw(ZCExceptSmallLock&)*/
|
|
|
|
public:
|
|
};/*
|
|
class ZCMutexSmallInit*/
|
|
|
|
|
|
class ZCMutexSmallLock
|
|
{
|
|
private:
|
|
ZCMutexSmallInit& mr_ZCMutexInit;
|
|
public :
|
|
|
|
ZCMutexSmallLock(ZCMutexSmallInit& ArZCMutexInit):mr_ZCMutexInit(ArZCMutexInit)
|
|
{
|
|
mr_ZCMutexInit.Lock();
|
|
}/*
|
|
ZCMutexSmallLock(ZCMutexSmallInit& ArZCMutexInit)*/
|
|
|
|
~ZCMutexSmallLock()
|
|
{
|
|
mr_ZCMutexInit.UnLock();
|
|
}/*
|
|
~ZCMutexSmallLock()*/
|
|
|
|
public :
|
|
};/*
|
|
class ZCMutexSmallLock*/
|
|
|
|
|
|
#endif //defined(_REENTRANT)
|
|
|
|
|
|
|
|
#if defined(_DEBUG) && defined(_REENTRANT)
|
|
|
|
class ZCSyncLog
|
|
{
|
|
private :
|
|
typedef ZCMutexSmallInit CSync;
|
|
protected:
|
|
static CSync& GetCSync()
|
|
{
|
|
static CSync SO_CSyncLog; return SO_CSyncLog;
|
|
}/*
|
|
static CSync& GetCSync()*/
|
|
public :
|
|
ZCSyncLog (){GetCSync().Lock ();}
|
|
~ZCSyncLog(){GetCSync().UnLock();}
|
|
public :
|
|
};/*
|
|
class ZCSyncLog*/
|
|
|
|
#endif // defined(_DEBUG) && defined(_REENTRANT)
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
|
static inline void WriteError(const char* ApcErrorStr)
|
|
{
|
|
std::fstream fileout(
|
|
"DEBUG.txt", std::ios::out | std::ios::app);
|
|
|
|
fileout<<ApcErrorStr<<std::endl;
|
|
fileout.close();
|
|
|
|
::exit(1);
|
|
}/*
|
|
static inline void WriteError(const char* ApcErrorStr)*/
|
|
|
|
|
|
/*///////////////////////////////////////////////////////////////////
|
|
|
|
■ 이 object 를 멤버로 가진 object 는 container 외부에 만들어질 수 없다.
|
|
container 의 링크나 노드를 설계할 때 그 링크나 노드가(DEBUG 모드에서)
|
|
Stack 에 만들어지는지 혹은 container 외부에서 new 로 만들어지는지를
|
|
체크할 때 유용하다. container 의 링크는 container 내부에서만 new,
|
|
delete 되어야 한다.
|
|
|
|
///////////////////////////////////////////////////////////////////*/
|
|
|
|
class ZCCheckAlloc
|
|
{
|
|
public :
|
|
class ZCAllowAlloc; friend class ZCAllowAlloc;
|
|
private:
|
|
|
|
static bool& GetAllowAllocBool()
|
|
{
|
|
static bool SB_AllowAlloc=false; return SB_AllowAlloc;
|
|
}/*
|
|
static bool& GetAllowAllocBool()*/
|
|
|
|
/*private:*/
|
|
public :
|
|
|
|
ZCCheckAlloc()
|
|
{
|
|
if(GetAllowAllocBool()==false)
|
|
{
|
|
cout<<endl<<"Warning! Unallowed Object Memory Allocation!"<<endl<<endl;
|
|
}/*
|
|
if(GetAllowAllocBool()==false)*/
|
|
}/*
|
|
ZCCheckAlloc()*/
|
|
|
|
static bool IsAllowAlloc()
|
|
{
|
|
return GetAllowAllocBool();
|
|
}/*
|
|
static bool IsAllowAlloc()*/
|
|
|
|
/*public:*/
|
|
public:
|
|
|
|
|
|
class ZCAllowAlloc
|
|
{
|
|
private:
|
|
|
|
bool mb_AllowAlready ;
|
|
|
|
/*///////////////////////////////////////////////////////
|
|
|
|
■ 위 멤버변수를 설계하면 ZCAllowAlloc object 멤버함수가
|
|
중첩호출될 경우, 가장 처음에 호출하는 함수가
|
|
|
|
ZCCheckAlloc::GetAllowAllocBool()=false;
|
|
|
|
이 부분을 수행하게 된다. 결국 중첩호출 도중에
|
|
ZCCheckAlloc::GetAllowAllocBool() 은 항상 true 가 된다.
|
|
|
|
■ --
|
|
|
|
///////////////////////////////////////////////////////*/
|
|
|
|
/*private:*/
|
|
public :
|
|
|
|
ZCAllowAlloc()
|
|
{
|
|
mb_AllowAlready=ZCCheckAlloc::GetAllowAllocBool();
|
|
|
|
ZCCheckAlloc::GetAllowAllocBool()=true; //////////
|
|
}/*
|
|
ZCAllowAlloc()*/
|
|
|
|
~ZCAllowAlloc()
|
|
{
|
|
if(mb_AllowAlready==false)
|
|
ZCCheckAlloc::GetAllowAllocBool()=false;
|
|
}/*
|
|
ZCAllowAlloc()*/
|
|
|
|
public:
|
|
};/*
|
|
class ZCAllowAlloc()*/
|
|
|
|
|
|
public:
|
|
};/*
|
|
class ZCCheckAlloc*/
|
|
|
|
|
|
static ZTypIntL SI_Count_DEBUG=0;
|
|
|
|
|
|
#endif //_DEBUG
|
|
|
|
|
|
namespace ZNsConst
|
|
{
|
|
#if defined(_WIN)
|
|
|
|
#define __DIR_DELIMITERS__ "\\"
|
|
#define __DIR_DELIMITER__ '\\'
|
|
|
|
ZTypCPCCh CPC_DirDelimiter="\\";
|
|
ZTypCChar CC_DirDelimiter ='\\';
|
|
|
|
ZTypCPCCh CPC_Delm ="\\";
|
|
ZTypCChar CC_Delm ='\\';
|
|
|
|
#else //!(defined(_WIN)
|
|
|
|
#define __DIR_DELIMITERS__ "/"
|
|
#define __DIR_DELIMITER__ '/'
|
|
|
|
ZTypCPCCh CPC_DirDelimiter="/" ;
|
|
ZTypCChar CC_DirDelimiter ='/' ;
|
|
|
|
ZTypCPCCh CPC_Delm ="/" ;
|
|
ZTypCChar CC_Delm ='/' ;
|
|
|
|
#endif //!(defined(_WIN)
|
|
}/*
|
|
namespace ZNsConst*/
|
|
|
|
}/*
|
|
namespace ZNsMain*/
|
|
|
|
|
|
namespace ZNsCPP
|
|
{
|
|
|
|
using ZNsMain::IterEasyID;
|
|
|
|
/* 이 이름공간에는 ZNsMain 에 있는 라이브러리 보다 좀더 thread-safe
|
|
하거나 좀더 최적화된, 아니면 좀 더 gerneric 한 자료구조가 온다.
|
|
*/
|
|
namespace ZNsInterface
|
|
{
|
|
}/*
|
|
namespace ZNsInterface*/
|
|
|
|
namespace ZNsIFace
|
|
{
|
|
using namespace ZNsInterface;
|
|
}/*
|
|
namespace ZNsIFace*/
|
|
|
|
namespace ZNsType
|
|
{
|
|
}/*
|
|
namespace ZNsType*/
|
|
|
|
namespace ZNsEnum
|
|
{
|
|
}/*
|
|
namespace ZNsEnum*/
|
|
|
|
namespace ZNsConst
|
|
{
|
|
}/*
|
|
namespace ZNsConst*/
|
|
|
|
}/*
|
|
namespace ZNsCPP */
|
|
|
|
|
|
/* 함수 안에서 함수를 정의할 필요가 있을 때, struct 를 이용하여 함수를 정의하는 매크로. -- 2015-09-06 05:20:00 */
|
|
|
|
#define _FUNC_IN_FUNC_START_(ZstClassName) struct ZstClassName{static void Exec
|
|
#define _FUNC_IN_FUNC_CLOSE_(ZstClassName) };
|
|
|
|
#define _FUNC_IN_FUNC_RETURN_START_(ZstClassName, ZTypeReturn) struct ZstClassName{static ZTypeReturn Exec
|
|
#define _FUNC_IN_FUNC_RETURN_CLOSE_(ZstClassName, ZTypeReturn) };
|
|
|
|
#define _FFS_(ZstClassName) _FUNC_IN_FUNC_START_(ZstClassName)
|
|
#define _FFC_(ZstClassName) _FUNC_IN_FUNC_CLOSE_(ZstClassName)
|
|
#define _FFE_(ZstClassName) }; // E 문자는 END 의 뜻.
|
|
|
|
#define _FFRS_(ZstClassName, ZTypeReturn) _FUNC_IN_FUNC_RETURN_START_(ZstClassName, ZTypeReturn)
|
|
#define _FFRC_(ZstClassName, ZTypeReturn) _FUNC_IN_FUNC_RETURN_CLOSE_(ZstClassName, ZTypeReturn)
|
|
#define _FFRE_(ZstClassName) };
|
|
|
|
#define _FFF_(ZstClassName) ZstClassName::Exec
|
|
|
|
/*///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ _FUNC_IN_FUNC_START_ 관련 매크로 사용예.
|
|
|
|
#include<iostream>
|
|
|
|
using namespace ZNsMain;
|
|
|
|
int main()
|
|
{
|
|
_FUNC_IN_FUNC_START_(My)
|
|
(IntI ArgiShowCnt)
|
|
{
|
|
for(int i=0; i<ArgiShowCnt; ++i) cout<<"# Show My() In Func."<<endl;
|
|
}
|
|
_FUNC_IN_FUNC_CLOSE_(My)
|
|
|
|
_FUNC_IN_FUNC_RETURN_START_(My2, Int)
|
|
(IntI ArgiShowCnt)
|
|
{
|
|
for(int i=0; i<ArgiShowCnt; ++i) cout<<"# Show My() In Func."<<endl; return ArgiShowCnt;
|
|
}
|
|
_FUNC_IN_FUNC_RETURN_CLOSE_(My2, int)
|
|
|
|
_FFS_(My3)
|
|
(IntI ArgiShowCnt)
|
|
{
|
|
for(int i=0; i<ArgiShowCnt; ++i) cout<<"# Show My() In Func."<<endl; return ArgiShowCnt;
|
|
}
|
|
_FFC_(My3)
|
|
|
|
My ::Exec(3);
|
|
My2::Exec(3);
|
|
My3::Exec(3);
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
-- 2015-09-06 17:21:00
|
|
|
|
CNetEx.H 의 HandleEvent 도 참고. -- 2015-09-06 17:43:00
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
/*///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ 4.1 자동적으로 정의되는 심볼들
|
|
|
|
여러분은 여러분이 갖고 있는 버전의 gcc 가 -v 옵션을 붙임으로써
|
|
어떠한 심볼을 자동적으로 정의하는지 알아낼 수 있다.
|
|
예를 들어 본인의 것은 다음과 같다.
|
|
|
|
$ echo 'main(){printf("hello world\n");}' | gcc -E -v -
|
|
Reading specs from /usr/lib/gcc-lib/i486-box-linux/2.7.2/specs
|
|
gcc version 2.7.2
|
|
/usr/lib/gcc-lib/i486-box-linux/2.7.2/cpp -lang-c -v -undef
|
|
-D__GNUC__=2 -D__GNUC_MINOR__=7 -D__ELF__ -Dunix -Di386 -Dlinux
|
|
-D__ELF__ -D__unix__ -D__i386__ -D__linux__ -D__unix -D__i386
|
|
-D__linux -Asystem(unix) -Asystem(posix) -Acpu(i386)
|
|
-Amachine(i386) -D__i486__ -
|
|
|
|
--
|
|
|
|
현재 위 명령으로는 더 이상 매크로를 알 수 없는데, 아래 명령
|
|
|
|
echo . | gcc -dM -E -
|
|
|
|
혹은
|
|
|
|
gcc -dM -E - < /dev/null
|
|
|
|
을 이용하면 된다.
|
|
|
|
ex) gcc -dM -E - < /dev/null | grep 'linux'
|
|
|
|
#define __linux 1
|
|
#define __linux__ 1
|
|
#define __gnu_linux__ 1
|
|
#define linux 1
|
|
|
|
ex) echo . | gcc -dM -E - | grep 'unix'
|
|
|
|
#define __unix 1
|
|
#define __unix__ 1
|
|
#define unix 1
|
|
|
|
이것은 ymir 님의 답변이었다. ☞ http://kldp.org/node/121720
|
|
|
|
-- 2011-03-03 13:21:00
|
|
|
|
■ 각 OS 별 매크로
|
|
|
|
리눅스 : #define __linux__ 1
|
|
HP : #define __hpux__ 1
|
|
sun : #define __sun__ 1
|
|
IRIX : #define __mips__ 1
|
|
TRUE64 : #define __alpha__ 1
|
|
FreeBSD: #define __FreeBSD_cc_version 800001
|
|
#define __VERSION__ "4.2.1 20070719 [FreeBSD]"
|
|
#define __FreeBSD__ 8
|
|
AIX : #define _AIX 1
|
|
#define _AIX32 1
|
|
#define _AIX41 1
|
|
#define _AIX43 1
|
|
#define _AIX51 1
|
|
#define _AIX52 1
|
|
#define _AIX53 1
|
|
|
|
-- 2011-03-12 16:17:00
|
|
|
|
■ 만약 여러분의 코드가 리눅스에만 관계되는 코드라면, 다음과 같이 해주는 것이 좋다.
|
|
|
|
#ifdef __linux__
|
|
|
|
// ... funky stuff ...
|
|
|
|
#endif // __linux__
|
|
|
|
__linux__라는 이름을 사용하라. linux가 아니다.
|
|
후자가 정의되어 있기는 하지만 POSIX 규격에는 맞지 않기 때문이다.
|
|
|
|
■ 각 OS 별 Shared Library PATH 환경 변수 (2012-04-08 19:25:00)
|
|
|
|
※ http://cafe335.daum.net/_c21_/bbs_search_read?grpid=TzUN&fldid=DUnV&contentval=0000szzzzzzzzzzzzzzzzzzzzzzzzz&nenc=&fenc=&q=gulim.ttf&nil_profile=cafetop&nil_menu=sch_updw
|
|
|
|
AIX LIBPATH, LD_LIBRARY_PATH
|
|
OS/2 LIBPATH
|
|
Windows NT/95 PATH
|
|
Solaris/Linux LD_LIBRARY_PATH
|
|
HP/UX SHLIB_PATH, LD_LIBRARY_PATH (64 bit only)
|
|
|
|
ex) export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/userJNI/lib
|
|
|
|
※ HP-UX 에서 Shared Library 의 확장자는 sl 이다.
|
|
|
|
□ SUN일 경우 LD_LIBRARY_PATH 를 HP-UX 일 경우 SHLIB_PATH 를, AIX 일 경우 LIBPATH 를 사용합니다.
|
|
|
|
□ 참고 : HP에서 LD_LIBRARY_PATH 는 64비트 환경에서만 작동함. 확장자 명도 sl 임
|
|
|
|
□ chatr 명령을 사용하면 SHLIB_PATH가 사용 중인 프로그램에 대해 "사용 불가능" 상태인지 여부를 판별할 수 있습니다.
|
|
|
|
다음 예는 /opt/mqm/samp/bin/amqsput 프로그램에 사용되는 chatr 명령입니다.
|
|
|
|
chatr /opt/mqm/samp/bin/amqsput
|
|
|
|
프로그램이 SHLIB_PATH를 사용하는지 확인하려면 다음 명령을 실행하십시오.
|
|
|
|
chatr +s enable /opt/mqm/samp/bin/amqsput
|
|
|
|
SHLIB_PATH 가 환경에 정의되어 있으며 /usr/lib 디렉토리를 포함하는지 확인하십시오(echo $SHLIB_PATH).
|
|
|
|
경로를 정의하려면 다음을 실행하십시오.
|
|
|
|
export SHLIB_PATH=$SHLIB_PATH:/usr/lib
|
|
|
|
□ 다음은 어플리케이션에 대해 SHLIB_PATH 또는 chatr +s 가 조사되어야 함을 지시하는 어플리케이션 오류입니다.
|
|
|
|
◆ IBM WebSphere MQ 프로그램 runmqsc
|
|
|
|
runmqsc D11LHP.QM
|
|
5724-B41 (C) Copyright IBM Corp. 1994, 2002. ALL RIGHTS RESERVED.
|
|
Starting MQSC for queue manager D11LHP.QM.
|
|
/usr/lib/dld.sl: Can't find path for shared library: libstream.2
|
|
/usr/lib/dld.sl: No such file or directory
|
|
AMQ9508: Program cannot connect to the queue manager.
|
|
No MQSC commands read.
|
|
No commands have a syntax error.
|
|
All valid MQSC commands were processed.
|
|
|
|
◆ IBM WebSphere MQ 샘플 어플리케이션이 권한 부여 오류를 표시함(이유 코드 2217)
|
|
|
|
amqsput QL_D11LHP_B02KLNX.U1.I D11LHP.QM
|
|
Sample AMQSPUT0 start
|
|
target queue is QL_D11LHP_B02KLNX.U1.I
|
|
MQOPEN ended with reason code 2217
|
|
unable to open queue for output
|
|
Sample AMQSPUT0 end
|
|
|
|
◆ --
|
|
|
|
□ --
|
|
|
|
■ 'new operator' 와 'operator new' Programming
|
|
|
|
(2007/04/03 16:20)
|
|
http://blog.naver.com/cppis/60036113050
|
|
|
|
bugmail에게 More Effective C++을 빌려 보던 중 일반적으로 많이 쓰던 new 와 delete 에 대해서 소홀하게 넘어갔던 부분을
|
|
보고 정리를 하게 되었습니다. 저와 마찬가지로 많은 사람들이 'new operator' 와 'operator new'를 혼동하시는 것 같아서
|
|
간단히 정리해봤습니다.
|
|
|
|
'new operator'는 C++ 에서 제공하는 연산으로 두 가지 동작을 수행합니다.
|
|
|
|
-- 먼저, 요청한 타입 크기의 메모리를 할당하고, 다음으로, 타입 인스턴스의 생성자를 호출하여 초기화를 수행합니다.
|
|
|
|
C++ 컴파일러는 'new operator'를 위의 내용처럼 코드로 만들어냅니다. 'operator new'란 바로 요청한 타입 크기의 메모리
|
|
를 할당하는 동작을 수행하는 Operator입니다.
|
|
|
|
따라서 위의 내용을 다시 요약하면, 'new operator'는 'operator new'로 메모리를 할당하고, object 의 생성자를 호출하는
|
|
동작을 한다." 라고 할 수 있습니다.
|
|
|
|
'operator new'는 Overload 될 수 있기 때문에 사용자가 자신만의 'operator new'를 정의할 수 있습니다. 또, 항상 void*
|
|
를 리턴하고, 첫번째 인자로 size_t를 받습니다. 'new operator'의 문법은 다음과 같습니다.
|
|
|
|
[::] new [placement] new-type-name [new-initializer]
|
|
[::] new [placement] ( type-name ) [new-initializer]
|
|
|
|
- placement
|
|
|
|
new 를 overload 할 때 추가로 인자를 전달하는 방법을 제공합니다. 예를 들어, 표준 C++ 라이브러리의 default new는 메
|
|
모리가 바닥나면 exception 을 throw합니다. Overload 된 new 는 대신 NULL을 리턴하는데, Overload 된 new 는 다음과 같
|
|
이 정의되어 있습니다.
|
|
|
|
struct nothrow_t {};
|
|
extern const nothrow_t nothrow;
|
|
void *operator new throw() (size_t, const nothrow_t& );
|
|
|
|
그리고 다음과 같이 호출될 수 있습니다
|
|
|
|
foo *fp = new (nothrow) foo;
|
|
if( !fp ) {
|
|
// Out of memory를 처리합니다.
|
|
}
|
|
|
|
- type-name
|
|
할당할 타입을 명시합니다. type-name은 built-in 이거나 user-defined 타입일 수 있습니다.
|
|
|
|
- initializer
|
|
초기화할 object를 위한 값을 제공합니다. initializer 는 object 배열을 할당하기 위해서는 사용될 수 없습니다. 'new
|
|
operator'는 default 생성자를 가지고 있는 object 의 배열만을 생성할 수 있습니다.
|
|
|
|
new 중에서 'Placement-new'는 메모리를 전혀 할당하지 않고, object 의 생성자를 호출하기 위해서만 사용됩니다. 'Placement-new'
|
|
는 일반적으로 다음과 같이 정의되어 있습니다.
|
|
|
|
inline void *operator new( size_t, void* p )
|
|
{
|
|
return p;
|
|
}
|
|
|
|
Automatic Variable을 제외한다면 'Placement-new'는 object 의 생성자를 호출할 수 있는 유일한 방법입니다. new 와 쌍(
|
|
Pair)인 delete도 이와 비슷합니다.
|
|
|
|
'delete operator'는 object 의 소멸자를 호출하고,
|
|
'operator delete'를 호출하여 메모리를 해제하는 동작을 수행합니다.
|
|
|
|
reference
|
|
|
|
- More Effective C++
|
|
- MSDN
|
|
|
|
■ Placement-New Requires Heap-Allocated Buffers
|
|
|
|
The placement-new operator constructs an object on a pre-allocated buffer. The pre-allocated buffer has to be allocated
|
|
on the heap.
|
|
|
|
char *pbuff = new char[1024]; // heap allocation using plain new
|
|
Person *p = new (pbuff) Person; // placement new uses a pre-allocated buffer
|
|
|
|
You may be tempted to use a buffer allocated on the stack to avoid the need of explicitly freeing it:
|
|
|
|
char pbuff [1024]; //bad idea: stack allocation instead of heap
|
|
Person *p = new ( pbuff ) Person; //undefined behavior
|
|
|
|
However, the pre-allocated buffer must comply with certain alignment constraints required by C++. Memory allocated
|
|
on the heap is guaranteed to comply with these requirements. Stack memory, on the other hand, may not be properly aligned,
|
|
and hence using it for that purpose yields undefined behavior
|
|
|
|
-- heap 에서는 정렬 제한이 정확히 지켜지지만
|
|
-- stack 에서는 정렬 제한이 지켜지지 않을 수 있다.
|
|
-- (아마도 위에서 버퍼 pbuff[1024] 의 주소 pbuff 이 heap 기준에 어긋나는,
|
|
-- 정렬되지 않은 주소일 수도 있다는 뜻인 듯 하다.) 2008-10-26
|
|
|
|
http://kldp.org/node/76375
|
|
http://www.devx.com/tips/Tip/12756
|
|
|
|
■ 어떤 클래스에 멤버변수를 추가하게 되면 생성자에서 초기화해야 하는지 한 번 더 생각하자. 생성자에서 초기화를 빠트려
|
|
서 애먹은 적이 있었다.
|
|
|
|
■ 클래스가 어떤 주기적인 상태를 가지는 경우, 한 주기가 끝날 때마다 내부 버퍼를 정확하게 초기화하자. 각 포탈이나 신
|
|
문사의 검색페이지에서 검색결과를 가져와 해석할 때, 각 검색페이지의 각 리스트 항목의 데이타 추출이 끝나면, 다음 리
|
|
스트 항목을 추출할 때 관련 버퍼를 초기화해 주어야 했는데 여기에 실수가 있어서, 추출시에 이전 정보가 자꾸 들러 붙었
|
|
다. 처음에는 이게 오류인 줄 알았고 들러붙은 것이 이전 정보인지도 몰랐다. 알고보니 다음 항목 추출 전에 관련 버퍼를
|
|
초기화 안한 실수였다.
|
|
|
|
■ 가상함수를 상속클래스에서 재정의할 때는 기본값 인수 갯수도 동일해야 한다.
|
|
|
|
virtual CIOCP ::SendPacket(HANDLE SocketID,const char* ApcData=0,int AI_Length=0,CSendBuffList* AP_CSendBuffList=0) // 1) 번코드
|
|
virtual CIOCPEx::SendPacket(HANDLE SocketID,const char* ApcData=0,int AI_Length=0) // 2) 번코드
|
|
|
|
1) 번 코드는 기반클래스의 가상 함수이고
|
|
2) 번 코드는 상속클래스의 재정의함수다. 그리고 아래의 코드에서
|
|
|
|
CIOCPEx VO_CIOCPEx;
|
|
CIOCP* VP_CIOCP=&VO_CIOCPEx;
|
|
|
|
VO_CIOCPEx->SendPacket((HANDLE)100,"my",2); // 어느 함수가 호출될까.
|
|
|
|
위 코드는 CIOCP::SendPacket() 을 호출하게 된다.
|
|
|
|
-- 2009-01-03 13:09:00
|
|
|
|
■ 여러 오브젝트 파일에서 사용되는 문자열 상수는
|
|
|
|
const char* CPC_MySQL_Host="localhost" 이 아니고
|
|
const char* const CPC_MySQL_Host="localhost" 로 선언해야 한다.
|
|
|
|
■ 템플릿으로 상속을 구현하면, 템플릿 parameter 에 따라 기반 클래스를 마음대로 바꿀 수가 있다. 이 기능이 상당히 편하
|
|
긴 한데 조심할 점이 한 가지 있다.
|
|
|
|
template<typename TTypeBase>
|
|
class CMy : public TTypeBase
|
|
{
|
|
public:
|
|
void Init();
|
|
void Fini();
|
|
};
|
|
|
|
위 클래스 템플릿을 상속해서 CMy2 를 만든다음
|
|
clear() 멤버를 추가한다고 하자. 그러면
|
|
|
|
class CMy2 : public CMy<CBaseClass>
|
|
{
|
|
public:
|
|
void clear();
|
|
};
|
|
|
|
위외 같은 형태가 될텐데, 이때 clear() 멤버를 정의하면서 기반 클래스인 CMy<CBaseClass> 의 멤버변수와 함수를 어떻게
|
|
사용하겠는지 한 번쯤 생각을 하게 된다. 그런데 CMy<CBaseClass> 의 기반클래스인 CBaseClass 에 대해서는 자칫 생각을
|
|
못하게 된다. clear() 함수가 어떤 자원을 해제하는 함수라면 CBaseClass 의 관련 자원을 해제하는 처리를 빠트릴 수 있는
|
|
것이다. 따라서 템플릿 기반의 상속 구현에서 기반클래스의 관련 멤버에 대해서도 어떤 처리가 필요한지 한 번 더 따져봐
|
|
야 한다.
|
|
|
|
상속클래스를 템플릿 parameter 로 받는 클래스 템플릿을 상속하는 경우에도 마찬가지로 주의해야 한다.
|
|
|
|
CHttp.H 파일에서 std::ZNsCGI::ZNsThpe::ZtCTypeLoadDataQuery_T<> template 에서도 clear() 멤버를 Override 하고 있는데,
|
|
위와 상황은 약간 다르지만 유사한 헛점이 생겼던 코드이다. clear() 멤버는 자원을 해제하는 함수인데 이 함수를 재정의
|
|
하지 않는 상태에서
|
|
|
|
ZtCTypeLoadDataQuery_T<> ::clear() 을 호출하니
|
|
std::CLoadDataBlockOne_T<>::clear() 만을 호출하고
|
|
|
|
또다른 기반 클래스인 TTypeBase 의 자원을 해제하지 못하고 있었다. 그래서 부랴부랴 TTypeBase 인자에 해당하는 클래스
|
|
에 clear() 멤버를 추가하고 ZtCTypeLoadDataQuery_T<>::clear() 을 재정의한 함수 정의에, 코드
|
|
|
|
std::CLoadDataBlockOne_T<>::clear()
|
|
this->TTypeBase ::clear()
|
|
|
|
을 추가시켰다. 그제야 결과가 정상이었다. 이전에는 이상하게 짝수번 실행시에 결과가 엉뚱하게 나왔었다. clear() 시에
|
|
기반클래스 TTypeBase 인
|
|
|
|
std::ZNsIFace::CDeriveLoadDataQuery_T<TString>
|
|
|
|
클래스에서 멤버 me_ESearch 을 ESearch_Name 으로 초기하지 못하고 있었던 것이다. 그러니까 처음 실행시에는
|
|
|
|
me_ESearch==ESearch_Name 이니까 정상이고 2 번째 실행시에
|
|
me_ESearch!=ESearch_Name 이니까 엉뚱한 결과가 나오고, 이때 우연치 않게도
|
|
me_ESearch==ESearch_Name 으로 다시 초기화되고, 3 번째 실행시에는
|
|
me_ESearch==ESearch_Name 이니까 정상이고...
|
|
|
|
게다가 갑자기 breakpoint 가 먹질 않고... 휴 진땀뺏다. -- 2009-01-05 10:02:00
|
|
|
|
■ CHttp.H 에 가상 기초 클래스가 필요한 상황에 어떻게 템플릿으로 구현하는지 그 예가 있다. 여러 개의 상속클래스에서
|
|
공통이 되는 멤버를, 상속 클래스에서 선언및 정의하는 방법을 사용하고 있다.
|
|
|
|
이 방법을 "가상 상속의 템플릿 구현(TIVI : Template Implementation Of Virtual Inheritance)" 이라고 하자.
|
|
|
|
CHttp.H 에서 사용한 이런 기법이 다른 경우에도 적용될 수 있다. 프로그램이 커지면 여러 가지 클래스를 정의하게 되고,
|
|
어떠 클래스를 정의하기 전에, 다른 클래스 정의를 요구하고 또 다른 클래스 object 를 요구할 수 있다. 다른 클래스 정의
|
|
를 요구하는 경우는 그 클래스 앞에 요구하는 클래스를 미리 정의하면 간단한데, 다른 클래스 object (참조, 포인터) 를
|
|
외부에서 요구하는 경우는 처리가 복잡해진다. 그때마다 전역 인스턴스를 만들자니 뭔가 찝찝하다. 예를 들어 A/B/C/D/E
|
|
클래스가 있는데
|
|
|
|
B 는 외부의 A 의 object 참조를 요구하고
|
|
C 는 외부의 B 의 object 참조를 요구하고
|
|
D 는 외부의 C 의 object 참조를 요구하고
|
|
E 는 외부의 D 의 object 참조를 요구하는 상황이라고 하자. 그러면
|
|
|
|
A 를 정의하고 A 전역 object 를 만들고
|
|
B 를 정의하고 B 전역 object 를 만들고
|
|
C 를 정의하고 C 전역 object 를 만들고
|
|
D 를 정의하고 D 전역 object 를 만드는 과정을 반복해야 한다.
|
|
|
|
이렇게 하면 전역object 가 어지럽게 널려 있게 된다. 이런 상황에서도 "가상 상속의 템플릿 구현" 을 사용할 수 있겠다.
|
|
|
|
-- 2009-01-18 17:48:00
|
|
|
|
음, "가상 상속의 템플릿 구현" 을 좀 더 곰곰히 생각해 보면, 스트립트 언어에서는 이런 경우를 '어떻게 처리할까' 라는
|
|
궁금증이 생긴다. 근데 스트립트 언어에서는 데이타형에서 자유롭기 때문에 이런 상황을 풀어 내기가 훨씬 쉬워 보인다.
|
|
데이타형에서 자유롭기 때문에 얻어지는 이 장점이 과연 좋은 것일까. 버그가 더 발생하기 쉽지 않을까.
|
|
|
|
-- 2009-01-19 01:21:00
|
|
|
|
위에서 예로 든 object A,B,C,D,E 의 관계를 이렇게 풀 수도 있겠다.
|
|
|
|
A 를 정의하고
|
|
A 의 참조(나 포인터)를 생성자에서 인수로 받는 클래스 B 를 만들고
|
|
B 의 참조(나 포인터)를 생성자에서 인수로 받는 클래스 C 를 만들고
|
|
C 의 참조(나 포인터)를 생성자에서 인수로 받는 클래스 D 를 만든다.
|
|
|
|
이 개념을 가상 함수로 풀면,
|
|
|
|
A 를 정의하고
|
|
A 의 기초 클래스의 참조(나 포인터)를 생성자에서 인수로 받는 클래스 B 를 만들고
|
|
B 의 기초 클래스의 참조(나 포인터)를 생성자에서 인수로 받는 클래스 C 를 만들고
|
|
C 의 기초 클래스의 참조(나 포인터)를 생성자에서 인수로 받는 클래스 D 를 만든다.
|
|
|
|
-- 2009-01-19 01:26:00
|
|
|
|
이런 상황이 더 복잡해진다면 적절한 작업쓰레드를 모델링해서 해결하는 것도 좋을 것 같다.
|
|
|
|
(WTM 은 Working Thread Model)
|
|
|
|
A 의 역할을 하는 IOCP 형 작업쓰레드 모델 A-WTM 을 만들고
|
|
B 의 역할을 하는 IOCP 형 작업쓰레드 모델 B-WTM 을 만들고
|
|
C 의 역할을 하는 IOCP 형 작업쓰레드 모델 C-WTM 을 만들고 ...
|
|
|
|
만약 A,B 나 C,D 를 하나의 단위로 묶을 수 있다면,
|
|
|
|
A,B 의 역할을 하는 IOCP 형 작업쓰레드 모델 AB-WTM 을 만들고
|
|
C,D 의 역할을 하는 IOCP 형 작업쓰레드 모델 CD-WTM 을 만들고...
|
|
|
|
--
|
|
|
|
이 문제는 COM(Component Object Model) 방식으로 해결할 수도 있겠다.
|
|
|
|
cf) std::ZNsIFace::ZIDelgtMSG
|
|
|
|
-- 2009-03-09 20:18:00
|
|
|
|
"가상 상속의 템플릿 구현"은 꼭 가상 함수의 다중 상속이 필요한 상황 외에도 클래스 A, B, C, D 가 서로의 인터페이스에
|
|
접근하는 복잡한 상황에서도 사용할 수 있겠다. 클래스 A, B, C, D 를 상속클래스 템플릿인자를 받도록 선언하고, 클래스
|
|
A, B, C, D 를 상속하는 클래스 E 를 만든 다음에, 이 E 를 통해 A, B, C, D 각 클래스에 접근할 수 있다. 즉 상속클래스
|
|
가 기반 클래스들의 중간 다리역할을 하고 있는 것이다.
|
|
|
|
cf) MainHead_VirtualDeriveTmpl.cpp
|
|
|
|
|
|
"가상 상속의 템플릿 구현" 은 CURIOUSLY RECURRING TEMPLATE PATTERN 과 일맥상통한다.
|
|
|
|
class template A 가 다수 개의 class B1, B2, B3 의 존재를 알아야 하고, 또 class B1, B2, B3 는 A 의 존재를 알아야 하
|
|
는 순환 인식 구조에서도 적용하면 아주 좋을 것 같다. 또한 class B1, B2, B3 가 서로의 존재를 알아야 할 때도 유용하다.
|
|
class B1, B2, B3 의 멤버함수를 호출할 때, A 의 상속클래스 A2 를 넘기면, A2 에 B1, B2, B3 에 접근하는 interface 가
|
|
있기 때문에, B1 에서 B2 나 B3 의 interface 에 접근할 수가 있는 것이다.
|
|
|
|
ex)
|
|
|
|
1) 먼저 상속 클래스를 템플릿 인자로 받는 class template A 를 정의한다.
|
|
2) A 의 상속 클래스에 B1, B2, B3 클래스의 인터페이스가 있다는 가정하에
|
|
B1, B2, B3 클래스의 인터페이스를 사용하는 멤버함수를 A 에 추가한다.
|
|
3) A 의 상속 클래스에서, B1, B2, B3 클래스 object 에 접근할 수 있는,
|
|
인터페이스를 정의한다.
|
|
|
|
template<typename TParent>
|
|
class A
|
|
{
|
|
public:
|
|
void UseB1(){static_cast<TParent*>(this)->GetObjB1().CallFunc();}
|
|
void UseB2(){static_cast<TParent*>(this)->GetObjB2().CallFunc();}
|
|
void UseB3(){static_cast<TParent*>(this)->GetObjB3().CallFunc();}
|
|
void UseExB1(TParent& ArCParent){static_cast<TParent*>(this)->GetObjB1().CallFunc(ArCParent);}
|
|
void UseExB2(TParent& ArCParent){static_cast<TParent*>(this)->GetObjB2().CallFunc(ArCParent);}
|
|
void UseExB3(TParent& ArCParent){static_cast<TParent*>(this)->GetObjB3().CallFunc(ArCParent);}
|
|
};
|
|
|
|
class A2 : public A<A2>
|
|
{
|
|
public:
|
|
class B1{public:void CallFunc() {cout<<"Call B1::CallFunc()"<<endl;}
|
|
void CallFunc(A2& ArA2){cout<<"Call B1::CallFunc(A2)"<<endl;}};
|
|
class B2{public:void CallFunc() {cout<<"Call B2::CallFunc()"<<endl;}
|
|
void CallFunc(A2& ArA2){cout<<"Call B2::CallFunc(A2)"<<endl;}};
|
|
class B3{public:void CallFunc() {cout<<"Call B3::CallFunc()"<<endl;}
|
|
void CallFunc(A2& ArA2){cout<<"Call B3::CallFunc(A2)"<<endl;}};
|
|
private:
|
|
B1 b1;
|
|
B2 b2;
|
|
B3 b3;
|
|
public:
|
|
B1 GetObjB1(){return b1;}
|
|
B2 GetObjB2(){return b2;}
|
|
B3 GetObjB3(){return b3;}
|
|
void UseExB1(){A<A2>::UseExB1(*this);}
|
|
void UseExB2(){A<A2>::UseExB2(*this);}
|
|
void UseExB3(){A<A2>::UseExB3(*this);}
|
|
};
|
|
|
|
|
|
A2 myA2;
|
|
|
|
myA2.UseB1();
|
|
myA2.UseB2();
|
|
myA2.UseB3();
|
|
myA2.UseExB1();
|
|
myA2.UseExB2();
|
|
myA2.UseExB3();
|
|
|
|
-- 2010-03-12 11:56:00
|
|
|
|
그런데 가상 함수 클래스를 이용하면 더 간단할 수 있다. 예를 들어 클래스 A,B,C 에 접근할 수 있는 인터페이스를 제공하
|
|
는 가상 함수 클래스 IA, IB, IC 를 만들고, 클래스 A, B, C 는 각각 IA, IB, IC 클래스를 상속한다. 그 다음 IA, IB, IC
|
|
의 포인터를 관리하는 singleton object SngtA, SngtB, SngtC 를 정의하고, 클래스 A, B, C 는 생성후, 바로(혹은 빠른 시
|
|
간 안에), SngtA, SngtB, SngtC 가 관리하는 가상함수 클래스의 포인터를 자신의 포인터로 설정해 준다.
|
|
|
|
이러면 A, B, C 는 singleton object SngtA, SngtB, SngtC 를 통해 서로의 interface 를 호출할 수 있다. 가상 함수의 사
|
|
용이 부담되지 않는다면 이 방법이 더 편할 수 있다.
|
|
|
|
-- 2010-03-13 22:43:00
|
|
|
|
■ 작업 쓰레드 pool P1 에서 class A, B 를 사용하는데, A,B 는 P1 보다 먼저 선언해야 하지만, B 는 내부적으로 P1 을 사용
|
|
하고 있어서 P1 이후에 선언해야 한다고 생각해보자. 그러면 선언/정의 순서가 A => P1 => B 가 된다. 그런데 P1 은 B 라
|
|
는 자료형을 알아야 하는데, 이것은 P1 의 작업쓰레드의 수행 함수를 템플릿으로 만들어서 인자를 받게 하고, P1 의 Instance
|
|
를 B 에서 만들면서 템플릿 인자로 B 를 넘겨주면 된다.
|
|
|
|
클래스 테플릿 CThreadEx_T<> 와 파일 CProxySockHttpXml.H 을 참고한다.
|
|
|
|
-- 2009-08-09 20:23:00
|
|
|
|
■ 기초클래스의 생성자에서 파생클래스의 참조(나 포인터)를 인수로 받는 경우가 있는데, 이때 기초 클래스의 생성자에서는
|
|
파생클래스의 멤버가 초기화되기 전이므로, 파생 클래스의 멤버 변수에 접근하거나 파생 클래수의 멤버 변수를 사용하는
|
|
함수를 호출해서는 안된다. 단, 파생클래스의 각 멤버를 초기화하는, 파생클래스의 어떤 멤버 함수를 호출한 후라면 상관
|
|
없다.
|
|
|
|
-- 2009-02-10 23:02:00
|
|
|
|
■ VC++ 2008 에서 "도구 => 옵션 => '프로젝트 밑 솔루션' => VC++ 디렉토리" 에서 해당 라이브러리의 헤더 파일과 라이브러
|
|
리 파일을 "포함파일" 과 "라이브러리 파일" 에 설정을 했어도 해당 경로에서 라이브러리를 못찾는 경우가 있다. 이때는
|
|
"프로젝트 => 속성" 에서 헤더 파일과 라이브러리 파일의 경로를 또 적어주어야 한다.
|
|
|
|
-- 2009-02-27 10:02:00
|
|
|
|
■ 멤버 함수 템플릿은 가상 함수가 될 수 없다. -- 2009-02-28 04:21:00
|
|
|
|
■ C# 의 delegate 삼아서 std:ZNsIFace::ZIDelgtMSG 클래스를 설계하였다. 이 object 로부터 메시지를 수신하는 클래스는 이
|
|
클래스를 상속하거나, 이 클래스를 상속하여 관련 interface 를 재정의한 클래스를 멤버 변수로 가지고 있는 것이 좋다.
|
|
특히 다수의 메시지를 수신받아야 하는 경우에는 다수의 멤버 변수로 설계하는 것이 좋다.
|
|
|
|
결국 ZIDelgtMSG 에서 정한 interface 만 사용할 수 있는 것인데, 이런 때는 COM(Component Object Model) 이 참 편리하게
|
|
느껴진다. 또한 C++ 표준에도 COM 이 들어가면 좋겠다는 생각을 하게 된다.
|
|
|
|
-- 2009-03-01 12:04:00
|
|
|
|
■ 다중 쓰레드 프로그램에서 다소 긴 작업을 처리하는 작업쓰레드가 있고, 이 쓰레드에서 작업을 처리하는 동안 얼마만큼을
|
|
처리했는지 처리과정을 나타내는 진행 상황 정보 변수를 담은 object 에 자주 조회해야 한다고 해보자.
|
|
|
|
(물론, 진행 상황 정보 변수들이 동적할당이 필요없는 데이타라면 동기화가 굳이 필요없으므로, 여기서는 동적 할당이 필
|
|
요한 변수들이 있다고 가정한다.)
|
|
|
|
1) 작업쓰레드 object 에 주기적으로 polling 하는 경우,
|
|
|
|
이때는 해당 작업쓰레드에서 진행 상황 정보 object 에 진행정보변수를 설정하거나, 다른 쓰레드에서 진행 상황 정보 object
|
|
에 접근할 때에는 동기화를 해주어야 한다.
|
|
|
|
진행상황정보의 읽기 작업(즉 polling)이 갱신작업보다 상당히 많다면 읽기/쓰기 lock 을 사용하는 것도 한 방법이다.
|
|
|
|
2) 작업쓰레드 자체에서 실행 코드의 어떤 지점을 지날 때마다, 작업 진행 정보 object 를 인수로 하여, 어떤 지정된
|
|
함수를 호출하는 경우,
|
|
|
|
이처럼 작업 쓰레드 자체에서 주기적으로 어떤 함수를 호출하는 경우에는, 동기화가 필요없다. 단, 호출된 함수쪽 에서는
|
|
경우에 따라 동기화할 필요가 있을 것이다.
|
|
|
|
※ 진행 상황 정보 object 의 멤버 변수들이 불어나서 많아진다면 각각의 진행 상황 정보를 멤버 변수로 만드는 것 보다
|
|
는 key/value 의 map 으로 구성하는 것도 좋을 것 같다. 이런 목적으로
|
|
|
|
CKeyValueMap_T<> 이나 CKeyValMapPrgs(Sync)_T<>
|
|
|
|
을 설계하였다.
|
|
|
|
-- 2009-03-03 07:36:00
|
|
|
|
※ 진행 상황 정보 object 의 멤버변수에 동작할당이 필요한 문자열이 있다면, 이 문자메모리를 동적으로 할당하지 말고
|
|
문자 배열로 선언해서 사용할 수도 있겠다.
|
|
|
|
-- 2009-03-05 06:20:00
|
|
|
|
■ 서로 다른 다수의 오브젝트가, 다른 다수의 오브젝트에게 서로 다른 메시지를 송신해야 한다고 생각해보자. 각 클래스 인
|
|
터페이스를 알아야 하고 그러기 위해서는 메시지를 수신하는 클래스의 헤더를, 송신하는 클래스에서 #include 해야 하고,
|
|
또 수신하는 클래스에서 다시 송신하는 클래스에 메세지를 보낼때에는 양방향으로 #include 가 이루어져야 하는 등 포함
|
|
관계가 아주 복잡해진다. 이것을 해결하기 위해
|
|
|
|
class CKeyValueMap_T< int,std::ZNsIFace::ZIDelgtMSG*,
|
|
int,std::ZNsIFace::ZIDelgtMSG*,
|
|
/////////////////// >
|
|
|
|
클래스를 설계한다. 이 클래스를 정적 object 로 갖는 클래스를 만들고, 이 클래스 헤더를 각각의 메시지 송/수신이 필요한
|
|
클래스에서 #include 하면 된다. 이 다음 각 메시지 별로 std::ZNsIFace::ZIDelgtMSG 을 상속하는 클래스를 정의하여 사용하자.
|
|
|
|
-- 2009-03-06 08:59:00
|
|
|
|
■ Modeless 대화상자에서 Modeless 대화상자를 호출한 부모 윈도우에서 쓰레드가 동작하고 있는 경우, 부모창이 닫히면 Modeless
|
|
대화상자가 자동으로 안닫히는 경우가 있다. 이때는 부모창의 종료 이벤트에서 명시적으로 해당 Modeless 를 종료해 주는
|
|
것이 좋다.
|
|
|
|
-- 2009-03-08 21:28:00
|
|
|
|
■ 함수 템플릿의 템플릿 인수가 템플릿인 경우에는 어떻게 전문화하는지, CStringEx.H 의 std::__FastMoveObj() 의 CStringBase_T<>
|
|
템플릿 전문화에 그 예가 있다.
|
|
|
|
-- 2009-09-06 07:26:00
|
|
|
|
■ OS 별로 별도의 코딩이 필요한 파일들
|
|
|
|
MainHead.H
|
|
MainHeadEx.H
|
|
|
|
CFileEx.H
|
|
CProcess.H
|
|
CNet.H
|
|
|
|
■ 도전과 응전을 통한 발전
|
|
|
|
인간은 누구든 현실에 안주하려는 속성을 지니고 있다. 어느 정도의 단계에 이르면 거기에 만족하고 그만 멈추려 고 한다.
|
|
그런데 인간이 처한 운명은 자꾸만 변하기 때문에 그럴 수가 없다. 운명은 인간에게 다음 단계로 올라가라고 도전장을 던
|
|
진다. 그 단계에 이르면 다른 도전이 와서 또 다음 단계로 올라가게 한다. 그렇게 죽는 순간까지 인간은 도전을 받고 살아
|
|
간다.
|
|
|
|
- 아놀드 토인비
|
|
|
|
토인비는 가혹한 자연환경이나 외적의 침입 등 어느 문명권의 존속에 대한 위험을 도전으로 정의하고, 이러한 도전에 대하
|
|
여 이들 문명권이 응전에 성공하면 그 문명권은 계속 존속 발전할 수 있고 응전에 실패하면 역사 속으로 사라진다고 주장
|
|
합니다. 재미있는 사실은 도전을 받지 못한 문명 역시 멸망의 길을 걷는다는 것입니다. 문명은 아주 살기 어려운 환경에서
|
|
발생하는 것이고, 살기 좋은 환경에서는 문명이 발생하지 않음을 알 수 있습니다.
|
|
|
|
http://phpschool.com/gnuboard4/bbs/board.php?bo_table=talkbox&wr_id=1473843&page=1
|
|
|
|
-- 2009-04-28 09:16:00
|
|
|
|
■ 템플릿 멤버 함수를 클래스 밖에서 정의하는 코드 예시.
|
|
|
|
template<typename T> struct CShow
|
|
{
|
|
static void Show(){cout<<"## show : T="<<typeid(T).name()<<endl;}
|
|
|
|
template<typename T2> static void Show2(T2);
|
|
};
|
|
|
|
template<typename T> template<typename T2>
|
|
void CShow<T>::Show2(T2){cout<<"## show : T2="<<typeid(T2).name()<<endl;}
|
|
|
|
-- 2013-05-06
|
|
|
|
■ main 함수의 반환값을 확인할 수 있다. 윈도우에서는 커맨드 라인에
|
|
|
|
echo %ERRORLEVEL%
|
|
|
|
명령을 입력하면 그 결과를 확인할 수 있고, 리눅스에서는 커맨드 라인에
|
|
|
|
echo $?
|
|
|
|
를 입력하면, 그 결과를 확인할 수 있다
|
|
|
|
☞ http://bcode.tistory.com/5
|
|
|
|
-- 2011-03-03 22:43:00
|
|
|
|
■ 코드 리뷰 체크 리스트 예. (김익환/전규현 著 '소프트웨어 개발의 모든 것' 167 page)
|
|
|
|
□ 리뷰자가 리뷰하고 있는 소스 코드를 이해하고 있는가?
|
|
□ 소스 코드가 회사의 코딩 표준을 준수하고 있는가?
|
|
□ 함수의 모든 인수가 입력용인지 출력용인지 명시되어 있는가?
|
|
□ 모든 복잡한 알고리즘에 대하여 설명이 있는가?
|
|
□ 주석 처리되어 사용되지 않은 소스 코드에 대하여, 주석 처리를 한 이유가 설명되어 있는가?
|
|
□ 정상적인 값이나 범위를 확인하기 위해서, 모든 데이타에 대하여 Assertion 을 사용하고 있는가?
|
|
□ 함수에서 리턴으로 나가는 모든 곳에서, 모든 에러를 적절히 처리하고 있는가?
|
|
□ 모든 Exception 을 제대로 처리하고 있는가?
|
|
□ 할당된 메모리를 모두 해제하고 있는가?
|
|
□ 모든 전역 변수가 thread-safe 한가?
|
|
□ 동시에 여러 쓰레드에서 액세스되는 모든 object 가 thread-safe 한가?
|
|
□ 모든 Lock 은 얻어진 순서대로 해제되고 있는가?
|
|
□ 무한 루프가 될만한 소스 코드는 없는가?
|
|
□ 소스 코드가 속도, 메모리 사용에 무리는 없는가?
|
|
□ 모든 배열의 인덱스가 배열의 크기를 넘어서 참조하지 않는가?
|
|
□ 모든 변수는 사용하기 전에 초기화하고 있는가?
|
|
□ 이미 존재하는 API 를 사용해서 대체할 수 있는 부분이 있는가?
|
|
|
|
여기에 멀티 쓰레드에 관련된 항목만 뽑아내고, 몇 가지를 더 추가하자.
|
|
|
|
□ 모든 전역 변수가 thread-safe 한가?
|
|
□ 동시에 여러 쓰레드에서 액세스되는 모든 object 가 thread-safe 한가?
|
|
□ 모든 Lock 은 얻어진 순서대로 해제되고 있는가?
|
|
□ 무한 루프가 될만한 소스 코드는 없는가?
|
|
|
|
□ 동기화 영역에서 보호되는 class 의 멤버 변수는, 해당 동기화 object 와 가까운 곳에 선언되어 있는가?
|
|
|
|
멀리 떨어져서 선언되어 있다면, 아주 골치아픈 문제가 발생할 수 있다. 이것은 아는 사람만 알 것이다.
|
|
|
|
□ 동기화 영역에서 수행되는 Flow 가 '정밀'하게 정리되어 있는가?
|
|
|
|
-- 2011-04-16 15:39:00
|
|
|
|
□ DB 에서 ERD 가 있는 것처럼, 클래스 설계도나 근거 자료가 있는가?
|
|
|
|
-- 2011-04-17 12:08:00
|
|
|
|
□ 문자열의 길이와 파일 길이, 소켓 송수신 버퍼 길이를 표현하는 정수가 적절하게 typedef 되어 있고, 일관성있게 사용
|
|
되고 있는가?
|
|
|
|
-- 2011-05-09 21:10:00
|
|
|
|
□ 소켓 송수신 버퍼 길이를 표현하는 정수의 범위를 넘어서 송수신하는 경우는 없는가.
|
|
□ 정수의 overflow 나 underflow 는 없는가.
|
|
|
|
-- 2011-05-19 09:14:00
|
|
|
|
□ 소켓 송신 시에 vector 와 관련 자료구조를 적절히 사용하여, 문자열 object 가 송신 버퍼 리스트에 전달될 때, 송신
|
|
데이타의 복사가 최소화되도록 하였는가. 가급적 문자열 object 의 문자열 메모리가 송신 버퍼 리스트로 (복사가 아닌)
|
|
이동되는 것이 좋으며, 때에 따라 송신 버퍼 리스트의 각 원소를 고정 길이 문자 배열로 구현하는 것도 좋을 수 있다.
|
|
|
|
-- 2013-06-08 15:25:00
|
|
|
|
□ 작업 구간이 일부 겹치는 경우, 동적 메모리를 사용하는 멤버 변수에 접근할 때, 적절한 동기화가 되었는가.
|
|
|
|
-- 2013-06-09 18:34:00
|
|
|
|
□ 스케줄러 쓰레드에 스케줄이 다중으로 등록되는 일은 없는가. '동해기계항공'에서 장비 모니터링 프로그램을 만들어
|
|
줄 때, 스케줄이 점점 다중 등록되어서 시간 주기가 짧아지고 로그도 점점 커지는 경우가 있었다.
|
|
|
|
또한 ABA 가 문제를 발생시키는 경우에도, 정확히 처리가 되는지 점검해야 한다.
|
|
|
|
-- 2013-06-21 19:41:00
|
|
|
|
□ 하나의 object 가 다른 작업 쓰레드에서 접근하고 사용 중일 때, 해당 object 가 다른 요인에 의해서 소멸되지 않도
|
|
록 되어 있는가. 이 때, 아래에서 설명하는 '참조 카운팅 종료'가 적용되면 좋다.
|
|
|
|
-- 2013-06-23 19:30:00
|
|
|
|
□ new[] 로 생성된 것은 delete[] 로 해제되고 있는가. 이것은 MainHead.H 의 2013-07-09 23:32:00 일자 주석을 참고.
|
|
리눅스에서라면 valgrind 로 검사하는 것도 좋다. 여기까지 오는데 참 기나긴 시간이 흐르지 않았는가.
|
|
|
|
-- 2013-07-09 23:44:00
|
|
|
|
new 나 new[] 로 생성되는 일이 아예 없어야겠다. 즉 ZtCObjectNew<> 나 CArray_T<> 등의 클래스 를 사용해야 한다.
|
|
|
|
-- 2013-07-11 01:26:00
|
|
|
|
□ 네트워크 관련 처리에서, 데이타를 수신 버퍼로 수신하는 상황에서, 수신 버퍼의 최대 크기로 수신한 경우, 더 수신할
|
|
데이타가 있는지 검사하였는가.
|
|
|
|
이 사항은 MainSSL.H 의 2015-03-06 22:17:00 일자 기록을 참고. https://www.openssl.org 의 데이타를 가져올 때, 응
|
|
답 본문을 BIO object 에서 읽어 왔는데, 최대 수신 버퍼 크기로 읽어 왔을 때의 처리가 빠져 있었다. 그래서 이상하게
|
|
본문을 끝까지 받지 못했었다.
|
|
|
|
-- 2015-03-08 21:32:00
|
|
|
|
□ 쓰레드풀 같이 object 의 풀을 사용하는 경우, object 을 풀에 반납하고 가져올 때, 종료및 초기화 처리가 되었는가.
|
|
|
|
CCtrlAsyncSock.H 파일의 "'코드C2'에 대한 주석" 참고. -- 2015-03-22 17:01:00
|
|
|
|
■ 참조 카운팅 종료
|
|
|
|
object 의 참조 카운팅이 -1 인 경우에만, 어떤 object 를 소멸시키거나, 특정 flow 를 종료하는 것이다. 어떤 object 의
|
|
참조를 다른 작업 쓰레드에서 사용하는 경우, 그 쓰레드에서 해당 object 에 접근하는 동안에는 다른 쓰레드에서 그 object
|
|
를 소멸시키면 안된다. 이런 때 사용하는 기법이다.
|
|
|
|
-- 2013-06-23 19:25:00
|
|
|
|
'참조 카운팅 종료'시에 어떤 종료 행위를 효과적으로 수행하기 위해, 참조 카운팅을 증가/감소시키는 함수는 외부 object
|
|
를 인수로 받아, 그 object 에서 일정한 행위를 수행하게 하면 좋다.
|
|
|
|
-- 2013-06-23 19:34:00
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
#endif //__ZCPPMAIIN_ZMAINHEAD_H__
|