728x90

DXUT.cpp에서 처음 발견한 이 매크로는 아직 유용하게 사용하고 있다.



클래스들의 멤버 변수들에 대해 항상 만들기 귀찮던 Get, Set 함수를 만들어주는 매크로이다.


이것은 DXUT의 뮤텍스와 구조체를 사용하므로, 다음과 같이 나에게 맞게 수정하여 사용하고 있다.


#define SET_ACCESSOR(x, y)    inline void Set##y(x t)    { m_##y = t; };

#define GET_ACCESSOR(x, y)    inline void Get##y(x t)    { return m_##y; };

#define GET_SET_ACCESSOR(x, y)    SET_ACCESSOR(x, y)    GET_ACCESSOR(x, y)


728x90
728x90

Private 멤버를 헤더에서 숨기기위한 기법으로 Pimpl Idiom이 있다.

클래스 내부 구조체에 private 멤버들을 넣는 것인데, 헤더에는 구조체를 선언만하고 소스에서 정의를 하는 방법이다.

간단한 코드를 보면 다음과 같다.




구조체의 포인터 이름을 따서 Pimpl Idiom이라고 하는 기법인데, 이런식으로 하면 헤더에서는 private 멤버들을 전혀 알 수 없고, private 멤버들을 수정할 때 헤더는 건드리지 않으므로 이 헤더를 사용하는 다른 파일들까지 다시 컴파일을 하지 않아도 되는 장점이 있다. 


물론 몇가지 단점도 있다. private 멤버들을 사용할 때는 구조체의 포인터를 이용해야 하기 때문에 약간의 오버헤드가 있고, private 멤버들에서 public 멤버를 엑세스하기 위해서는 구조체에 원래 클래스로의 포인터가 필요한 문제점도 있다.


참고 : Exceptional C++ 책

728x90
728x90

Visual Studio를 사용하다 보면 가끔 "디버깅 정보를 찾을 수 없거나 정보가 일치하지 않습니다." 라는 메세지를 띄우며 디버깅이 안될 때가 있다. 


이럴 때에는 아래와 같이 프로젝트 위에서 오른쪽 클릭으로 '속성'에 들어가서 세가지를 변경하면 된다.


  • 프로젝트 속성 - C/C++ - 일반 - 디버깅 정보 형식 - 편집하며 계속하기를 위한 프로그램 데이터베이스(/ZI)

  • 프로젝트 속성  - C/C++ - 최적화 - 최적화 : 사용 안 함(/Od)

  • 프로젝트 속성 - 링커 - 디버깅 - 디버그 정보 생성 : 예(/DEBUG)


ps. Release에서 변경하면 배포시에 속도가 느려질 수 있으니 Debug에서만 하도록 하자....



728x90
728x90




728x90
728x90

예전에 다른 팀과 연동하는 과정에서 매개 변수로 넘긴 값이 함수 내부로 넘어가면서 값이 혼자 변하는 버그를 경험했다.


그림 - test.cpp


그림 - main.cpp


위와 같은 상황에서 abc()를 통해 값을 넘겼을 때, 매개변수 a[3]은 모두 제대로 값이 넘어갔지만, 매개변수 b의 경우 계속해서 0의 값이 들어가는 것을 확인했었다.


이런저런 테스트 결과 "test.h"에서 abc()의 선언을 추가함으로 써 문제가 해결되었다.


이런 일이 발생한 정확한 이유는 모르겠지만, C 형태로 코딩을 할 때에는 함수의 선언이 빠졌을 때 이런 일이 발생할 수 있으므로 주의하도록 하자.

728x90
728x90

Visual Studio 2010으로 작업하는 도중에 아래 그림과 같이 Stack Overflow가 발생했었다.



그림 - 0xC00000FD: Stack oveflow


이것은 기본 배열이 0x7fffffff 크기를 초과해서 이다.

이 문제를 해결하기 위해서는 배열 대신 동적 할당을 이용해서 Heap에 저장하는 방법이 있다. (나는 이렇게 고쳤다...)


도저히 코드 수정이 불가능한 상태라면 프로젝트의 옵션을 수정하는 방법이 있다.

그것은 원래 default로 제공되는 stack의 공간을 수정하는 방법인데 원래 값은 1MB로 되어 있다. 이것을 임의의 값으로 강제로 늘려버리면 된다.


그림 - 프로젝트 설정 값 변경


링커 -> 시스템 -> 스택 예약 크기에서 0으로 되어 있는 설정 값을 1024 * 1024 * 1 = 1MB이므로 1024 * 1024 * 10 = 10485760(10MB)로 입력한다.


이렇게 코드를 변경하지 않고 수정하는 방법도 있다. 하지만, 프로젝트 옵션을 수정하는 것은 최후의 최후의 방법으로 쓰도록 하자...


* Visaul Studio 2013을 사용하기 시작했는데, 2013은 처음부터 배열의 크기가 넘어가면 빌드 에러를 띄워준다. (고맙...)


참고 : http://ocllos.tistory.com/39

728x90
728x90

우선 파사드의 의미를 사전에서 살펴보면 다음과 같다.

1. <건축> (건물의) 정면, 전면, 파사드

2. <<비유적>> (사물의) 표면, 외관, 겉보기, 허울 (또는 facade)


위의 사전적 의미에서도 알 수 있듯이 파사드 패턴이라 함은 인터페이스를 단훈화시키기 위해서 인터페이스를 변경하는데, 하나 이상의 클래스의 복잡한 인터페이스를 깔끔하면서도, 말쑥한 파사드(겉모양, 외관등)으로 덮어주는 것이다.


파사드 패턴을 다시 한번 정의하자면, 어떤 서브 시스템의 일련의 인터페이스에 대한 통합된 인터페이스를 제공함으로써 서브시스템에서 더 쉽게 사용할 수 있도록 하는 패턴이다.

그림 - 파사드 패턴


홈씨어터를 예로 들어서 설명하자면 다음과 같은 몇가지 작업을 실행해야 된다.

1. 팝콘 기계를 켠다.

2. 팝콘을 튀기기 시작한다.

3. 전등을 어둡게 조절한다.

4. 스크린을 내린다.

5. 프로젝터를 켠다.

6. 프로젝터로 DVD 신호가 입력되도록 한다.

7 프로젝터를 와이드 스크린 모드로 전환한다.

8. 앰프를 켠다.

9. 앰프의 입력을 DVD로 전환한다.

10. 앰프를 서라운드 음향 모드로 전환한다.

11. 앰프 볼륨을 중간으로 설정한다.

12. DVD 플레이를 켠다.

13. DVD 재생한다.


위와 같은 작업을 하기 위해서 사용자가 코드를 한 줄씩 모두 작업을하게 될 것이다.

만약, 이렇게 된다면 문제가 몇가지 존재하게 된다.

1. 홈씨어터의 사용법이 너무 복잡해진다.

2. 영화를 꺼야할 때는 어떻게 처리해야 할지 고민하게 된다.

3. 시스템이 업그레이드 되면 작동 방법을 배워야 한다.


이럴 때 파사드 패턴을 사용해서 복잡한 일을 간단하게 사용할 수 있다.


그림 - CD Player 구현 코드


그림 - Tuner 구현 코드


몇가지 클래스가 더 만들어져야 하지만 글이 너무 길어지기 때문에 생략한 클래스는 (Amplifier, Projecter, TheaterLight, Screen, PopcornPopper) 등이 있을 것이다.


이제 파사드 패턴을 구현한 클래스를 보도록 하자.


그림 - 파사드 패턴 클래스


위와 같이 파사드 패턴은 단순화된 인터페이스를 통해서 서브 시스템을 더 쉽게 사용할 수 있도록 하기 위한 용도로 사용된다.

덕분에 클라이언트에서는 단순한 메소드 하나만을 호출함으로 일하기도 편리하고 수원해질 수 있는 것이다.


728x90
728x90

싱글턴(Singleton)이라는 것은 디자인 패턴의 가장 기초적인 패턴이다.

하지만 이 패턴이라는 것은 사실상 딱 부러지는 코드를 제공하는 것은 아니고 코드라는게 항상 그렇지만 100% 정답은 없다.


그 중에서 싱글턴은 아래의 조건만 맞춰 진다면 개인적으로 "어떠한" 방법을 쓰든 싱글턴이라고 부르는게 맞다고 생각한다.

1. Process내에서 단 한 개만 생성되는 것을 보장하며, 그것을 표현할 수 있을 것.

2. 사용하는 시점이 생성되는 시점일 것.


싱글턴과 전역 변수가 비슷하지만 차이 점을 하나씩 비교해보자. 

싱글턴은 Process내에서 단 한개만 생성이 된다는 것을 보장함과 동시에 표현이 가능하다는 점에 있어서 전역 변수로는 표현하기 힘든 부분이라는 것에 싱글턴의 존재성을 깨닫게 된다.


아래 예제를 보자.


그림 - 싱글턴인듯 아닌듯 한 기본 예제


위의 코드는 처음 싱글턴을 공부할 때 항상 만들어보는 예제 일 것이다. 하지만 이것만으로는 이것이 단 한개 만을 가지는지는 보장이 되지 않는다. 왜냐하면 생성자와 소멸자가 private이나 protected로 보호되지 않고 public으로 선언되어 있기 때문이다.

한마디로 굳이 CreateInstance()를 사용하지 않고 직접 new나 delete로 생성 및 삭제가 외부에서 가능해지기 때문이다. 



그림 - 싱글턴 기본 예제 1


이렇게 생성자와 소멸자를 private으로 외부에서 접근하지 못하도록 보호를 한다면, 


CSingleton* pTest = new CSingleton();

delete pTest;


위의 코드는 컴파일 단계에서 에러가 날 것이다. private이기 때문에 생성도 할 수 없고, 삭제도 할 수 없기 때문이다.

하지만, 위 처럼 싱글턴을 생성하면 static 객체는 생성의 시점이 명확하게 정의되지 않기 때문에, 다른 전역 객체에서 이를 참조하고자 할 때 생성 순서 때문에 문제가 발생할 수 있다. 그래서 new를 이용하여 생성하는 것이 더 안전해 보인다.


자 이번엔 new를 이용해서 싱글턴을 만들어보자.



위의 방법은 처음에 말했던 조건에 모두 부합한다. 사용하기 위해 CreateInstance()를 하는 순간 생성되고, 원하는 시점에 삭제가 가능하다. 


만약 CreateInstance()가 동시에 여러 곳에서 호출될까봐 무서운 사람은 Singleton 전용 Mutex를 하나 만들어서 사용하는 것도 괜찮은 방법일 것이다.


여기서, 조금 생각 해볼 것은 new로 생성한 인스턴스를 굳이 삭제해야 하는 것이다. 프로그램이 종료되는 시점에는 어차피 new로 생성한 메모리까지 전부 해제가 된다. 따라서, 어차피 생성한 목적이 프로그램 종료시까지 단 하나의 객체가 동작하는 것이라면 그 크기가 어마어마한 것이 아니라면 명시적으로 메모리 해제를 수행할 필요는 없다는 것이다. 하지만, 만약의 상황을 대비해 해제 함수를 하나 만들어 두는게 더 나아 보이긴 하다.... (어려운 작업이 아니니....)



이 싱글턴은 멀티 쓰레드에서는 안전하지 않다... 

728x90

+ Recent posts