SlideShare a Scribd company logo
1 of 66
아꿈사
http://cafe.naver.com/architect1
박진호
http://blog.naver.com/jinojjan
 Pimpl 이디엄
 싱글톤과 팩토리 메서드
 프록시, 어댑터와 퍼사드
 옵저버
 내부의 구체적인 코드를 public 헤더 파일로
부터 완전히 숨김
 기본적으로 private 멤버 변수와 함수를 .cpp
파일에 위치 시킴
공개 인터페이스
Public:
Function1()
Function2()
Protected:
Function3()
Private:
Impl* pImpl 내부 구현
Public:
PrivateFuntion1()
PrivateFunction2()
PrivateData1
privateData2
pImpl 이디엄은 숨겨진 구현 클래스를 내부 포인터로 가리키는 공개
클래스를 말함
// autotimer.h
#ifdef WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif
#include <string>
class AutoTimer
{
public:
/// Create a new timer object with a human readable name
explicit AutoTimer(const std::string &name);
/// On destruction, the timer reports how long it was alive
AutoTimer();
private:
// Return how long the object has been alive
double GetElapsed() const;
std::string mName;
#ifdef WIN32
DWORD mStartTime;
#else
struct timeval mStartTime;
#endif
// autotimer.h
#include <string>
class AutoTimer
{
public:
explicit AutoTimer(const std::string &name);
AutoTimer();
private:
class Impl;
Impl *mImpl;
};
#include "autotimer.h"
#include <iostream>
#if_WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif
class AutoTimer::Impl
{
public:
double GetElapsed() const
{
#ifdef _WIN32
return (GetTickCount() - mStartTime) / 1e3;
#else
struct timeval end_time;
gettimeofday(&end_time, NULL);
double t1 = mStartTime.tv_usec / 1e6 + mStartTime.tv_sec;
double t2 = end_time.tv_usec / 1e6 + end_time.tv_sec;
return t2-t1;
#endif
}
std::string mName;
#ifdef _WIN32
DWORD mStartTime;
#else
struct timeval mStartTime;
#endif
AutoTimer::AutoTimer(const std::string &name) : mImpl(new AutoTimer::Impl())
{
mImpl->mName name;
#ifdef _WIN32
mImpl->mStartTime = GetTickCount();
#else
gettimeofday(&mImpl->mStartTime, NULL);
#endif
}
AutoTimer::AutoTimer()
{
std::cout << mImpl >mName << ": took " << mImpl >GetElapsed() << " secs" << std::endl;
delete mImpl;
mImpl = NULL;
}
AutoTimer::AutoTimer(const std::string &name) : mImpl(new AutoTimer::Impl())
{
mImpl->mName name;
#ifdef _WIN32
mImpl->mStartTime = GetTickCount();
#else
gettimeofday(&mImpl->mStartTime, NULL);
#endif
}
AutoTimer::AutoTimer()
{
std::cout << mImpl >mName << ": took " << mImpl >GetElapsed() << " secs" << std::endl;
delete mImpl;
mImpl = NULL;
}
1. Private 멤버 변수만을 포함한다.
2. Private 멤버 변수와 함수를 포함한다.
3. Public 클래스의 모든 함수와 대응되는 함수
를 Impl 클래스에 구현한다.
 기본적으로 얕은 복사가 사용됨.
 다음의 2가지 선택사항을 취해 얕은 복사 시
예상치 못한 오류 발생 예방
 클래스를 복사할 수 없게 만듦
▪ Private으로 복사 생성자 선언 및 할당 연산자 선언
 깊은 복사 기능을 명시적으로 정의
 정보 은닉
 #define prive public
 #include “yourapi.h”
 #undef private
 의존성 제거
 Windows.h 및 sys/time.h에 대한 의존성 없앰
 빠른 컴파일
 Api 계층 구조가 줄어듦
 뛰어난 이진 호환성
 Pimpl 이디엄 포함한 객체의 크기는 절대 바뀌지 않음
 지연 할당
 Pimpl 클래스는 필요할 때 생성되기 때문에 네트워크 연결과
같은 제한된 또는 많은 비용이 드는 리소스를 사용할 때 유용
 Pimpl 구현 객체를 메모리에 할당하고 해제해야하는 문제.
 포인터의 크기 때문에 객체 크기 역시 늘어나서 모든 변수 접근에
필요한 간접 참조의 성능 문제 발생
 New와 delete 호출에 따른 추가적인 비용
▪ 빠른 Pimpl 이디엄(new와 delete 연산자를 오버로드 해서 적은 메모리를 사
용하도록 고정된 크기의 메모리 할당자를 사용하는 효율적인 메모리 사용 방
법)
 코드를 읽는 것, 디버깅 하는것도 어려워 짐.
 상수 함수 안에 있는 변수들은 분리된 객체 안에 존재하기 때문에
컴파일러는 이 변수들의 값 변화를 더 이상 감지할 수없음.
void PimpledObject::ConstMethod() const
{
mImpl->mName = "string changed by a const method";
}
 페이지 112 ~ 114 참고
 어떻게 싱글톤 객체를 할당할 것인가?
 언제 싱글톤 객체를 파괴 시킬 것인가?
 쓰레드 안정성을 지원하는 가?
 쭉정이(알맹이가 없는) 싱글턴을 사용하면
어떻게 되는가?
 발전된 형태의 전역 변수
 프로그램 상에서 하나의 인스턴스만 있고
두번째 인스턴스를 만들 수 없는 기능
 쓰임에 따라 최선의 방법들이 달라짐
 기본 생성자를 private에 선언
 외부에서 new로 객체 생성 불가
 Singleton* pObject = new Singleton();  컴파일 에러
 복사 생성자, 복사 대입연산자 도 private에 선언
 복사로 인한 생성 불가
 정의를 하지 않고 선언만 함
(정의가 있으면 멤버함수 혹은 프렌드 함수가 호출 할 수 있기 때문에 정의
하지 않음)
 복사 생성자
▪ Singleton object1( Singleton::GetInstance() );  컴파일 에러
 복사 대입 연산자
▪ Singleton& object1 = Singleton::GetInstance();
▪ Singleton& object2 = Singleton::GetInstance();
▪ object1 = object2;  컴파일 에러
 .h
 .cpp
 Static 클래스 멤버 변수는 static 전역 변수처럼 프로그램
시작 시 main() 함수 호출 이전에 초기화
 싱글톤 객체 사용하지 않더라도 무조건 생성되기 때문
에 비효율적
 정적 객체는 다른 전역객체의 생성자에서 참고하고 싶
은 경우 문제 발생 할 수 있음
 C++ 표준에서는 전역 객체들의 생성 순서에 대해 명확하게 정
의하고 있지 않기 때문
 Main() 함수가 실행 하기 전에만 생성되면 됨
 어떤 전역 객체의 생성자에서 위 싱글톤 객체를 참조하려고
할 경우 싱글톤 객체가 생성되기 전인 경우 문제 발생 할 수 있
음
 .h
 .cpp
 최초 GetInstace() 를 호출하는 시점에 객체가
생성
 한번도 해당 객체를 생성하지 않으면 객체 생
성 하지 않으므로 자원을 효율적으로 사용
 다른 전역 객체의 생성자에서 참조하는 것도
가능
 프로그램이 종료되는 순간 동적 객체는 자동으
로 해제되기 때문에 굳이 명시적으로 해제할
필요 없음
 프로그램을 종료하기 위해 exit() 가 수행하는 cleanup 과정 (C++ 기준)
1. 현재 thread의 thread storage duration 내에 있는 object 들을 모두
소멸 ( C++11 only)
2. static storage duration의 object들을 소멸
1. Static storage duration
2. Thread storage duration
3. Automatic storage duration
4. Dynamic storage duration
3. atexit 에 등록되어 있는 함수들을 호출
4. 모든 C stream(stdin, stdout, stderr 등등) 과 tmpfile 에 의해 생성된
파일들을 비우고 닫음
5. 제어권이 host environment 로 넘어감
 두번째 싱글톤 객체가 반드시 프로그램 종료
시 반납해야 하는 외부 시스템 자원을 사용하
는 경우 사용
 싱글턴 객체를 이용하여, OS 리소스 를 만들고 해제
하지 않는다면 "리소스 릭:Resource Leak" 이 발생
 싱글턴 객체의 소멸자에 리소스 해제 기능을 놓고,
싱글턴 객체를 파괴 함 으로써 이러한 문제 해결
 Ateexit() 함수를 사용
 다른 전역 객체의 소멸자를 이용
 #include <stdlib.h>
 int atexit(void (*func)(void));
 함수 호출 성공 시 0, 실패 시 0 아닌 값 반환.
 반환형과 매개변수 형이 void로 선언된 함수의 이름이(주소 값이)
atexit함수의 인자로 전달
 인자로 전달된 함수가 프로그램 종료 시 자동으로 호출되며, 이렇게 자
동으로 호출되어야 할 함수는 32개 이상 등록할 수 있음.
 atexit 함수의 특성
 등록된 순서의 역순으로 호출
 atexit 함수를 통해서 등록된 함수는 프로그램이 정상적으로 종료될 때에만
호출
 .h
.cpp
 .h
.cpp
 명시적 해제 작업을 피하기 위해 static 지역 객
체 사용
1. 지역 static 객체는 전역 static 객체와 달리 해당 함수를
처음 호출 하는 시점에 초기화
2. 위 객체를 한번도 사용하지 않으면 생성되지 않음
3. Static 이므로 프로그램 종료 시 까지 객체가 유지
4. 종료시에는 자동으로 소멸자 호출
 로그 객체, 키보드 객체, 모니터 객체가 존재하며, 네번째 싱글톤으로 구성
(1)키보드 객체를 생성하고, 모니터 객체를 생성 하는 중 실패하여,
(2)로그 객체를 생성하여 로그를 찍음
(3)그리고 프로그램이 종료 작업에 들어 가게 됨.
 에러 상황
(4) 로그 객체는 먼저 삭제됨.
(5)키보드 객체를 파괴할 때, 실패하여,
(6)로그 객체를 이용해 로그를 찍으려 함
하지만, 로그 객체는 이미 파괴된 후이므로, 쭉정이 싱글톤에 접근하게 되어, 크래
쉬가 발생
 상황 분석
 static 을 이용하기 때문에, 스택 형태로 메모리에 올라와져 있어, 키보드 객체가 파괴되기 전 로
그 객체 부터 파괴.
 왜냐하면 로그 객체가 키보드 객체 후에 만들어졌기 때문
 네번째 싱글톤 객체를 다른 전역 객체의 소멸
자에서 사용하려고 하면 문제 발생
 C++ 표준에서는 전역 객체들의 생성 순서만 명시하
지 않은 것이 아니라 소멸 순서에 대해서도 명시해
놓지 않음
 어떤 전역 객체가 소멸자에서 저 싱글톤 객체를 사
용하려고 할 때 싱글톤 객체가 먼저 소멸했다면 문
제가 발생 (참조 무효화)
 싱글톤 참조 시 해당 객체의 소멸 여부를 파악
하고 만약 소멸했다면 되살림
 싱글턴의 파괴 시점을 조작
 Static 지역 변수의 특징
 메모리의 생성은 프로그램이 static 지역변수 가 포함된
함수를 호출해야 생성
 프로그램 종료 시점에 메모리 파괴가 일어난다 해도 그
공간은 빈 공간으로 남아 있음( 다른것으로 채워지지
않음)
 위 특징 사용.
 프로그램 종료 시점에 그 메모리 공간에 다시 쓰기 위
해 replacement new를 사용
 파괴 시점을 제어하기 위해 std::atexit함수 사용
 Replacement new
 이미 할당된 메모리 공간에 생성자만 호출
 일반 new처럼 사용하되 인자로 메모리가 할당되어있는 포인터를
넘겨줌
 내부적으로 void* operator new(size_t, void*) 원형의 new를 호출
 Ex)
 void* pBase = malloc(sizeof(CBase));
 new(pBase) CBase;
 메모리를 재할당 하지 않음
 기존 데이터가 그대로 남아있고, 생성자에서 초기화하는 데이터
만 초기화
 가상함수 테이블을 초기화
 메모리풀링 등에서 유용하게 사용
 .h
 .cpp
Static 객체의 생성/소멸 시점에 대해 정확히 파악해서 싱글톤 객체를 전
역 객체의 생성/ 소멸자에서 마구잡이로 참조하는 일이 없도록 주의해서
프로그래밍 해야함
 고려해야 할 사항
 싱글턴 객체의 생성 동기화
 고려해야 할 사항
 싱글턴 객체의 생성 동기화
 멀티 스레드 환경 지원 안함
 쓰레드A가 GetInstance() 함수 진입
 1번 조건 체크 하고 다음 줄 실행 전에 중지
 쓰레드 B가 GetInstance() 함수에 진입
 쓰레드 B는 s_pInstance가 NULL 이므로 1번 계속 진행.

 쓰레드 B는 2번 실행하여 객체 생성 후 호출자에게 instance 리턴
 쓰레드A는 다시 진행 됨. 2번이 다시 호출되어 또다른 인스턴스 생성
A쓰레드 B쓰레드
2번
1번
2번
1번
B쓰레드
널일 경우에만 락을 획득 하기 위함
위 조건 체크와 락을 얻을 때 사이에 다른 스
레드가 먼저 들어와서 pInstance를 초기화 할
수 있기 때문에 한번더 null 인지 체크
 s_pInstance = new LazySingleton(); 의미
 1. Singleton 객체를 담기 위한 메모리를 할당
 2. 할당된 메모리에 Singleton 객체를 생성
 3. s_pInstance가 할당된 메모리를 가리키도록 함
 컴파일러가 이 순서대로 수행되도록 제한하지
않음. 컴파일러는 때때로 스텝 2와 스텝 3사이의
순서를 바꾸기도 함
 A쓰레드에서 s_pInstance가 할당된 메모리
를 가리키도록 하고 그 후에 할당된 메모리
에 객체를 생성 해야 하는데 할당 전에
 B 쓰레드에서 싱글턴 객체를 바로 사용할 경
우 껍데기를 접근하여 문제 발생
 (싱글턴 객체는 메모리를 가리키기만 하고
실제 객체객체 생성은 안된 상황)
 Volatile 한정 지시자 사용
 volatile로 선언된 개체(변수, 메모리 위치, 코드)는
optimize 룰을 적용하지 말라.
 ( Objects declared as volatile are not used in certain
optimizations ( 출처 - MSDN ))
 컴파일러가 효율 등을 고려해 optimize 관점에서 코
드를 임의로 변경(의미 없는 코드 삭제나 실행 순서
변경)을 시키지 않음
 volatile로 선언된 개체는 메모리에 할당되고 작업 요
청시 직접(해당 주소에), 바로(효율을 위한 지연 없
이) 처리된다.
 volatile 키워드를 사용해야 할 곳이 있다면 C++11에
서는 atomic 변수를 사용
 C++11에서는 '서로 다른 스레드 간에 순서 관계가 정
의 되지 않은 메모리 읽기 쓰기 조작은 data race에
의한 알 수 없는 동작을 한다' 라고 되어 있음.
 즉 C++11에서 volatile 변수는 Memory Barrier 동작을
한다고 명시하지 않음
 메모리 바리어는 대부분 낮은 수준의 기계어에서 사
용되며 여러 장치가 공유하는 메모리를 사용하는 데
쓰임
 Lazy Instance 모델 대신 코드가 실행되는 시점,
main() 이 호출되기 전이나 뮤텍스 잠금으로
API가 초기화 시점에 초기화
 정적 초기화
static Singleton& foo = Singleton::GetInstance();
 명시적 API 초기화
Void APIInitialize()
{
Mutex mutex;
ScopredLock(&mutex);
Singleton::GetInstance();
}
 의존성 삽입
class MyClass
{
public:
MyClass() : mDatabase( new Database ("mydb, "localhost", "user", "pass"))
{}
private:
Database* mDatabase;
}
class MyClass
{
public:
MyClass(Database* db) : mDatabase(db)
{}
private:
Database* mDatabase;
}
 모노스테이트 패턴
 싱글톤의 문제는 전역 상태를 유지하고 접근하는데서 발생
// monostate.h
class MonoState
{
public:
int GetTheAnswer() const { return sAnswer; }
private:
static int sAnswer;
};
// monostate.cpp
int MonoState::sAnswer = 42;
 세션 문맥 사용
 C++ 생성자에서의 제약 사항
 결과 값 리턴 불가
 명명 규칙의 제약
 정적 형식의 객체 생성
 가상 생성자의 부재
 팩토리 메서드는 위 제약사항에 구애받지
않음
// renderer.h
#include <string>
class IRenderer
{
public:
virtual IRenderer() {}
virtual bool LoadScene(const std::string &filename) 0;
virtual void SetViewportSize(int w, int h) 0;
virtual void SetCameraPosition(double x, double y, double z) 0;
virtual void SetLookAt(double x, double y, double z) 0;
virtual void Render() 0;
};
// rendererfactory.h
#include "renderer.h"
#include <string>
class RendererFactory
{
public:
IRenderer *CreateRenderer(const std::string &type);
};
// rendererfactory.cpp
#include "rendererfactory.h"
#include "openglrenderer.h"
#include "directxrenderer.h"
#include "mesarenderer.h“
IRenderer *RendererFactory::CreateRenderer(const std::string &type)
{
if (type "opengl")
return new OpenGLRenderer();
if (type "directx")
return new DirectXRenderer();
if (type "mesa")
return new MesaRenderer();
return NULL;
 사용자가 원하는 타입의 인스턴스를 런타임
시에 생성하기 때문에 유연성 제공
 상속 클래스의 헤더 파일은 팩토리를 구현
하는 .cpp 파일에만 존재하며 public으로 선
언된 RenererFacory.h 파일에는 포함하지 않
음
 그러나 이것은 사용자에게 새로운 그래픽
처리기를 제공하지 못함.
 팩토리 메서드와 상속 클래스간의 연결 관
계를 느슨하게 만듦
 런타임시에 새로운 상속 클래스를 추가할
수 있도록 타입 이름을 객체 생성 콜백 함수
에 연결시키는 맵을 팩토리 클래스에서 사
용
// rendererfactory.h
#include "renderer.h"
#include <string>
#include <map>
class RendererFactory
{
public:
typedef IRenderer *(*CreateCallback)();
static void RegisterRenderer(const std::string &type, CreateCallback cb);
static void UnregisterRenderer(const std::string &type);
static IRenderer *CreateRenderer(const std::string &type);
private:
typedef std::map<std::string, CreateCallback> CallbackMap;
static CallbackMap mRenderers;
};
#include "rendererfactory.h"
// instantiate the static variable in RendererFactory
RendererFactory::CallbackMap RendererFactory::mRenderers;
void RendererFactory::RegisterRenderer(const std::string &type, CreateCallback cb)
{
mRenderers[type] cb;
}
void RendererFactory::UnregisterRenderer(const std::string &type)
{
mRenderers.erase(type);
}
IRenderer *RendererFactory::CreateRenderer(const std::string &type)
{
CallbackMap::iterator it mRenderers.find(type);
if (it ! mRenderers.end())
{
// call the creation callback to construct this derived type
return (it >second)();
}
return NULL;
}
class UserRenderer : public IRenderer
{
public:
UserRenderer() {}
bool LoadScene(const std::string &filename) { return true; }
void SetViewportSize(int w, int h) {}
void SetCameraPosition(double x, double y, double z) {}
void SetLookAt(double x, double y, double z) {}
void Render() { std::cout << "User Render" << std::endl; }
static IRenderer *Create() { return new UserRenderer(); }
};
int main(int, char **)
{
// register a new renderer
RendererFactory::RegisterRenderer("user", UserRenderer::Create);
// create an instance of our new renderer
IRenderer *r RendererFactory::CreateRenderer("user");
r->Render();
delete r;
return 0;
}
 한 클래스의 인터페이스를 클라이언트에서
사용하고자 하는 다른 인터페이스로 변환
어댑터를 이용하면 인터페이스 호환성 문제
때문에 같이 쓸 수 없는 클래스들을 연결해
서 쓸 수 있음.
public class Adapter implements target{
request(){
translatedRequest();
}
}
클라이언트와 어댑티는 서로 분리
서로 상대방에 대해서 전혀 모름.
어댑터에서 타겟 인터페이스를 구현
어댑터는 어댑티로 구성
모든 요청은 어댑티에게 위임
public class Adapter implements target{
request(){
specificRequest();
}
}
객체 구성(Composition) 사용
어댑티의 어떤 서브클래스에 대해서도 어댑터
를 쓸 수 있다는 장점
클라이언트를 특정 구현이 아닌 인터페이스에 연결
- 여러 어댑터 사용 가능
- 타겟 인터페이스만 제대로 지키다면 다른 구현
추가 가능
다중상속을 사용해서 어댑
터를 어댑티와 타켓 클랙스
모두의 서브클래스로 만듦.
※ 자바에서는 실제로 동작하지 않는 코드입니다
public class Adapter extends Target, Adaptee{
public void request(){
specificRequest();
}
}
- 어댑티 전체는 다시 구현하지 않아도 됨
- 어댑티의 행동을 오버라이딩 가능
- 구성을 사용하기 때문에 그 서
브클래스에 대해서도 어댑터
역할을 할 수 있음
 어떤 서브시스템의 일련의 인터페이스에 대한 통합된 인터페이스를 제공
퍼사드에서 고수준 인터페이스를 정의하기 때문에 서브시스템을 더 쉽게 사용할 수 있
음
클래스 다이어그램
1. 일대다 관계 (one-to-many)
• 상태를 저장하고 지배하는 것은 주제 객체.
• 옵저버는 여러 개가 있을 수 있지만,
주제 객체에서 상태가 바뀌었다는 것을 알려주기
를
기다리는 주제에 의존 적인 성질을 가짐.
2. 의존성
1. 옵저버는 주제 객체가 데이터를 갱신해 주기를
기다리는 입장 이기 때문에 의존성을 가짐.
2. 이런 방식으로 인해
깔끔한 객체지향 디자인을 만들 수 있음.
update()
<interface>
Observer
regosterObserver() { … }
removeObserver() { … }
notifyObservers() { … }
getState( )
setState( )
ConcreateSubject
regosterObserver()
removeObserver()
notifyObservers()
<interface>
Subject
update()
//기타 해당 옵저버의 메소
드
ConcreateObserver
옵저버
주제
옵저버가 될 가능성
이 있는 객체는 해당
인터페이스 상속.
옵저버를
등록/탈퇴/공지 하는
기능
상태를 설정하는
메소드가 필요
• 옵저버 패턴
한 객체의 상태가 바뀌면 그 객체
에 의존하는 다른 객체들한테 연락
이 가고 자동으로 내용이 갱신되는
방식으로 일대다(one-to-many) 의
존성을 정의
 옵저버 패턴에서는 주제와 옵저버가 느슨하게 결합되어 있는
객체 디자인을 제공.
 주제가 옵저버에 대해 아는 것은 옵저버가 특정 인터페이스를
구현(implements) 한다는 것 뿐.
 옵저버는 언제든지 새로 추가할 수 있음
 새로운 형식의 옵저버를 추가하려고 할 때도 주제를 전혀 변경
할 필요가 없음.
 주제와 옵저버는 서로 독립적으로 재사용할 수 있음.
 주제나 옵저버가 바뀌더라도 서로한테 영향을 미치지 않음.
감사합니다

More Related Content

What's hot

파이썬 병렬프로그래밍
파이썬 병렬프로그래밍파이썬 병렬프로그래밍
파이썬 병렬프로그래밍Yong Joon Moon
 
이것이 자바다 Chap. 6 클래스(CLASS)(KOR)
이것이 자바다 Chap. 6 클래스(CLASS)(KOR)이것이 자바다 Chap. 6 클래스(CLASS)(KOR)
이것이 자바다 Chap. 6 클래스(CLASS)(KOR)MIN SEOK KOO
 
Swift3 typecasting nested_type
Swift3 typecasting nested_typeSwift3 typecasting nested_type
Swift3 typecasting nested_typeEunjoo Im
 
Swift3 subscript inheritance initialization
Swift3 subscript inheritance initializationSwift3 subscript inheritance initialization
Swift3 subscript inheritance initializationEunjoo Im
 
스위프트, 코틀린과 모던언어의 특징 (Swift, Kotlin and Modern Languages)
스위프트, 코틀린과 모던언어의 특징 (Swift, Kotlin and Modern Languages)스위프트, 코틀린과 모던언어의 특징 (Swift, Kotlin and Modern Languages)
스위프트, 코틀린과 모던언어의 특징 (Swift, Kotlin and Modern Languages)Yongha Yoo
 
이펙티브 C++ 공부
이펙티브 C++ 공부이펙티브 C++ 공부
이펙티브 C++ 공부quxn6
 
Swift3 generic
Swift3 genericSwift3 generic
Swift3 genericEunjoo Im
 
C++ Advanced 강의 4주차
 C++ Advanced 강의 4주차 C++ Advanced 강의 4주차
C++ Advanced 강의 4주차HyunJoon Park
 
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)MIN SEOK KOO
 
이펙티브 C++ 스터디
이펙티브 C++ 스터디이펙티브 C++ 스터디
이펙티브 C++ 스터디quxn6
 
이펙티브 C++ 5,6 장 스터디
이펙티브 C++ 5,6 장 스터디이펙티브 C++ 5,6 장 스터디
이펙티브 C++ 5,6 장 스터디quxn6
 
동기화, 스케줄링
동기화, 스케줄링동기화, 스케줄링
동기화, 스케줄링xxbdxx
 
Effective c++ 정리 chapter 4
Effective c++ 정리 chapter 4Effective c++ 정리 chapter 4
Effective c++ 정리 chapter 4연우 김
 
이펙티브 C++ (7~9)
이펙티브 C++ (7~9)이펙티브 C++ (7~9)
이펙티브 C++ (7~9)익성 조
 
파이썬 함수 이해하기
파이썬 함수 이해하기 파이썬 함수 이해하기
파이썬 함수 이해하기 Yong Joon Moon
 
0.javascript기본(~3일차내)
0.javascript기본(~3일차내)0.javascript기본(~3일차내)
0.javascript기본(~3일차내)Sung-hoon Ma
 
Effective c++chapter1 and2
Effective c++chapter1 and2Effective c++chapter1 and2
Effective c++chapter1 and2성연 김
 
Effective c++chapter4
Effective c++chapter4Effective c++chapter4
Effective c++chapter4성연 김
 

What's hot (20)

파이썬 병렬프로그래밍
파이썬 병렬프로그래밍파이썬 병렬프로그래밍
파이썬 병렬프로그래밍
 
이것이 자바다 Chap. 6 클래스(CLASS)(KOR)
이것이 자바다 Chap. 6 클래스(CLASS)(KOR)이것이 자바다 Chap. 6 클래스(CLASS)(KOR)
이것이 자바다 Chap. 6 클래스(CLASS)(KOR)
 
Swift3 typecasting nested_type
Swift3 typecasting nested_typeSwift3 typecasting nested_type
Swift3 typecasting nested_type
 
Swift3 subscript inheritance initialization
Swift3 subscript inheritance initializationSwift3 subscript inheritance initialization
Swift3 subscript inheritance initialization
 
스위프트, 코틀린과 모던언어의 특징 (Swift, Kotlin and Modern Languages)
스위프트, 코틀린과 모던언어의 특징 (Swift, Kotlin and Modern Languages)스위프트, 코틀린과 모던언어의 특징 (Swift, Kotlin and Modern Languages)
스위프트, 코틀린과 모던언어의 특징 (Swift, Kotlin and Modern Languages)
 
이펙티브 C++ 공부
이펙티브 C++ 공부이펙티브 C++ 공부
이펙티브 C++ 공부
 
Swift3 generic
Swift3 genericSwift3 generic
Swift3 generic
 
Java lambda
Java lambdaJava lambda
Java lambda
 
C++ Advanced 강의 4주차
 C++ Advanced 강의 4주차 C++ Advanced 강의 4주차
C++ Advanced 강의 4주차
 
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
 
이펙티브 C++ 스터디
이펙티브 C++ 스터디이펙티브 C++ 스터디
이펙티브 C++ 스터디
 
이펙티브 C++ 5,6 장 스터디
이펙티브 C++ 5,6 장 스터디이펙티브 C++ 5,6 장 스터디
이펙티브 C++ 5,6 장 스터디
 
동기화, 스케줄링
동기화, 스케줄링동기화, 스케줄링
동기화, 스케줄링
 
Anatomy of Realm
Anatomy of RealmAnatomy of Realm
Anatomy of Realm
 
Effective c++ 정리 chapter 4
Effective c++ 정리 chapter 4Effective c++ 정리 chapter 4
Effective c++ 정리 chapter 4
 
이펙티브 C++ (7~9)
이펙티브 C++ (7~9)이펙티브 C++ (7~9)
이펙티브 C++ (7~9)
 
파이썬 함수 이해하기
파이썬 함수 이해하기 파이썬 함수 이해하기
파이썬 함수 이해하기
 
0.javascript기본(~3일차내)
0.javascript기본(~3일차내)0.javascript기본(~3일차내)
0.javascript기본(~3일차내)
 
Effective c++chapter1 and2
Effective c++chapter1 and2Effective c++chapter1 and2
Effective c++chapter1 and2
 
Effective c++chapter4
Effective c++chapter4Effective c++chapter4
Effective c++chapter4
 

Viewers also liked

제2회 사내기술세미나-no sql(배표용)-d-hankim-2013-4-30
제2회 사내기술세미나-no sql(배표용)-d-hankim-2013-4-30제2회 사내기술세미나-no sql(배표용)-d-hankim-2013-4-30
제2회 사내기술세미나-no sql(배표용)-d-hankim-2013-4-30Donghan Kim
 
Node Js와 Redis를 사용한 구조화된 데이터
Node Js와 Redis를 사용한 구조화된 데이터Node Js와 Redis를 사용한 구조화된 데이터
Node Js와 Redis를 사용한 구조화된 데이터jinho park
 
파이콘 한국 2017 키노트 : Back to the Basic
파이콘 한국 2017 키노트 : Back to the Basic파이콘 한국 2017 키노트 : Back to the Basic
파이콘 한국 2017 키노트 : Back to the BasicHyun-woo Park
 
NoSQL 모델링
NoSQL 모델링NoSQL 모델링
NoSQL 모델링Hoyong Lee
 
정보사회학
정보사회학정보사회학
정보사회학Il-woo Lee
 
NoSQL Database
NoSQL DatabaseNoSQL Database
NoSQL DatabaseSteve Min
 
NoSQL distilled 왜 NoSQL인가
NoSQL distilled 왜 NoSQL인가NoSQL distilled 왜 NoSQL인가
NoSQL distilled 왜 NoSQL인가Choonghyun Yang
 
Do not use Django as like as SMARTSTUDY
Do not use Django as like as SMARTSTUDYDo not use Django as like as SMARTSTUDY
Do not use Django as like as SMARTSTUDYHyun-woo Park
 
Docker.소개.30 m
Docker.소개.30 mDocker.소개.30 m
Docker.소개.30 mWonchang Song
 
NoSQL 분석 Slamdata
NoSQL 분석 SlamdataNoSQL 분석 Slamdata
NoSQL 분석 SlamdataPikdata Inc.
 
NoSQL 동향
NoSQL 동향NoSQL 동향
NoSQL 동향NAVER D2
 
[NoSQL] 2장. 집합적 데이터 모델
[NoSQL] 2장. 집합적 데이터 모델[NoSQL] 2장. 집합적 데이터 모델
[NoSQL] 2장. 집합적 데이터 모델kidoki
 
No sql 5장 일관성
No sql 5장   일관성No sql 5장   일관성
No sql 5장 일관성rooya85
 
개인정보 비식별화 기술 동향 및 전망
개인정보 비식별화 기술 동향 및 전망 개인정보 비식별화 기술 동향 및 전망
개인정보 비식별화 기술 동향 및 전망 Donghan Kim
 
Apache Spark Overview part2 (20161117)
Apache Spark Overview part2 (20161117)Apache Spark Overview part2 (20161117)
Apache Spark Overview part2 (20161117)Steve Min
 
NoSQL distilled.그래프 데이터베이스
NoSQL distilled.그래프 데이터베이스NoSQL distilled.그래프 데이터베이스
NoSQL distilled.그래프 데이터베이스Choonghyun Yang
 

Viewers also liked (20)

제2회 사내기술세미나-no sql(배표용)-d-hankim-2013-4-30
제2회 사내기술세미나-no sql(배표용)-d-hankim-2013-4-30제2회 사내기술세미나-no sql(배표용)-d-hankim-2013-4-30
제2회 사내기술세미나-no sql(배표용)-d-hankim-2013-4-30
 
Node Js와 Redis를 사용한 구조화된 데이터
Node Js와 Redis를 사용한 구조화된 데이터Node Js와 Redis를 사용한 구조화된 데이터
Node Js와 Redis를 사용한 구조화된 데이터
 
파이콘 한국 2017 키노트 : Back to the Basic
파이콘 한국 2017 키노트 : Back to the Basic파이콘 한국 2017 키노트 : Back to the Basic
파이콘 한국 2017 키노트 : Back to the Basic
 
NoSQL 모델링
NoSQL 모델링NoSQL 모델링
NoSQL 모델링
 
TRIZ
TRIZTRIZ
TRIZ
 
정보사회학
정보사회학정보사회학
정보사회학
 
NoSQL Database
NoSQL DatabaseNoSQL Database
NoSQL Database
 
NoSQL distilled 왜 NoSQL인가
NoSQL distilled 왜 NoSQL인가NoSQL distilled 왜 NoSQL인가
NoSQL distilled 왜 NoSQL인가
 
Do not use Django as like as SMARTSTUDY
Do not use Django as like as SMARTSTUDYDo not use Django as like as SMARTSTUDY
Do not use Django as like as SMARTSTUDY
 
Docker.소개.30 m
Docker.소개.30 mDocker.소개.30 m
Docker.소개.30 m
 
NoSQL 분석 Slamdata
NoSQL 분석 SlamdataNoSQL 분석 Slamdata
NoSQL 분석 Slamdata
 
NoSQL 동향
NoSQL 동향NoSQL 동향
NoSQL 동향
 
[NoSQL] 2장. 집합적 데이터 모델
[NoSQL] 2장. 집합적 데이터 모델[NoSQL] 2장. 집합적 데이터 모델
[NoSQL] 2장. 집합적 데이터 모델
 
Big data
Big dataBig data
Big data
 
No sql 5장 일관성
No sql 5장   일관성No sql 5장   일관성
No sql 5장 일관성
 
개인정보 비식별화 기술 동향 및 전망
개인정보 비식별화 기술 동향 및 전망 개인정보 비식별화 기술 동향 및 전망
개인정보 비식별화 기술 동향 및 전망
 
Express 프레임워크
Express 프레임워크Express 프레임워크
Express 프레임워크
 
Apache Spark Overview part2 (20161117)
Apache Spark Overview part2 (20161117)Apache Spark Overview part2 (20161117)
Apache Spark Overview part2 (20161117)
 
No sql 분산모델
No sql 분산모델No sql 분산모델
No sql 분산모델
 
NoSQL distilled.그래프 데이터베이스
NoSQL distilled.그래프 데이터베이스NoSQL distilled.그래프 데이터베이스
NoSQL distilled.그래프 데이터베이스
 

Similar to Api design for c++ ch3 pattern

Effective c++ 1~8장
Effective c++ 1~8장 Effective c++ 1~8장
Effective c++ 1~8장 Shin heemin
 
Effective c++ Chapter1,2
Effective c++ Chapter1,2Effective c++ Chapter1,2
Effective c++ Chapter1,2문익 장
 
Effective c++ 1,2
Effective c++ 1,2Effective c++ 1,2
Effective c++ 1,2세빈 정
 
Effective c++ chapter1 2_dcshin
Effective c++ chapter1 2_dcshinEffective c++ chapter1 2_dcshin
Effective c++ chapter1 2_dcshinDong Chan Shin
 
Java 강의자료 ed11
Java 강의자료 ed11Java 강의자료 ed11
Java 강의자료 ed11hungrok
 
Effective c++ chapter 1,2 요약
Effective c++ chapter 1,2 요약Effective c++ chapter 1,2 요약
Effective c++ chapter 1,2 요약Nam Hyeonuk
 
모어 이펙티브 c++ 5장 스터디
모어 이펙티브 c++ 5장 스터디모어 이펙티브 c++ 5장 스터디
모어 이펙티브 c++ 5장 스터디quxn6
 
Modern C++ 프로그래머를 위한 CPP11/14 핵심
Modern C++ 프로그래머를 위한 CPP11/14 핵심Modern C++ 프로그래머를 위한 CPP11/14 핵심
Modern C++ 프로그래머를 위한 CPP11/14 핵심흥배 최
 
More Effective C++ 4주차
More Effective C++ 4주차More Effective C++ 4주차
More Effective C++ 4주차Injae Lee
 
[Gpg2권]1.1 c++ 게임의 최적화
[Gpg2권]1.1 c++ 게임의 최적화[Gpg2권]1.1 c++ 게임의 최적화
[Gpg2권]1.1 c++ 게임의 최적화KyeongWon Koo
 
모어이펙티브 C++ 3,4장 예외, 효율 스터디
모어이펙티브 C++ 3,4장 예외, 효율 스터디모어이펙티브 C++ 3,4장 예외, 효율 스터디
모어이펙티브 C++ 3,4장 예외, 효율 스터디quxn6
 
Effective C++ Chapter 3 Summary
Effective C++ Chapter 3 SummaryEffective C++ Chapter 3 Summary
Effective C++ Chapter 3 SummarySeungYeonChoi10
 
HolubOnPatterns/chapter3_3
HolubOnPatterns/chapter3_3HolubOnPatterns/chapter3_3
HolubOnPatterns/chapter3_3suitzero
 
Effective c++(chapter 5,6)
Effective c++(chapter 5,6)Effective c++(chapter 5,6)
Effective c++(chapter 5,6)문익 장
 
Tcpl 14장 예외처리
Tcpl 14장 예외처리Tcpl 14장 예외처리
Tcpl 14장 예외처리재정 이
 
HolubOnPatterns/chapter2_2
HolubOnPatterns/chapter2_2HolubOnPatterns/chapter2_2
HolubOnPatterns/chapter2_2SeungHyun Hwang
 
Windows via c++ part 1
Windows via c++ part 1Windows via c++ part 1
Windows via c++ part 1Shin heemin
 
04 안드로이드 응용프로그램의 구조
04 안드로이드 응용프로그램의 구조04 안드로이드 응용프로그램의 구조
04 안드로이드 응용프로그램의 구조Wanbok Choi
 
게임프로그래밍입문 7
게임프로그래밍입문 7게임프로그래밍입문 7
게임프로그래밍입문 7Yeonah Ki
 

Similar to Api design for c++ ch3 pattern (20)

Effective c++ 1~8장
Effective c++ 1~8장 Effective c++ 1~8장
Effective c++ 1~8장
 
Effective c++ Chapter1,2
Effective c++ Chapter1,2Effective c++ Chapter1,2
Effective c++ Chapter1,2
 
Effective c++ 1,2
Effective c++ 1,2Effective c++ 1,2
Effective c++ 1,2
 
MEC++ 5
MEC++ 5MEC++ 5
MEC++ 5
 
Effective c++ chapter1 2_dcshin
Effective c++ chapter1 2_dcshinEffective c++ chapter1 2_dcshin
Effective c++ chapter1 2_dcshin
 
Java 강의자료 ed11
Java 강의자료 ed11Java 강의자료 ed11
Java 강의자료 ed11
 
Effective c++ chapter 1,2 요약
Effective c++ chapter 1,2 요약Effective c++ chapter 1,2 요약
Effective c++ chapter 1,2 요약
 
모어 이펙티브 c++ 5장 스터디
모어 이펙티브 c++ 5장 스터디모어 이펙티브 c++ 5장 스터디
모어 이펙티브 c++ 5장 스터디
 
Modern C++ 프로그래머를 위한 CPP11/14 핵심
Modern C++ 프로그래머를 위한 CPP11/14 핵심Modern C++ 프로그래머를 위한 CPP11/14 핵심
Modern C++ 프로그래머를 위한 CPP11/14 핵심
 
More Effective C++ 4주차
More Effective C++ 4주차More Effective C++ 4주차
More Effective C++ 4주차
 
[Gpg2권]1.1 c++ 게임의 최적화
[Gpg2권]1.1 c++ 게임의 최적화[Gpg2권]1.1 c++ 게임의 최적화
[Gpg2권]1.1 c++ 게임의 최적화
 
모어이펙티브 C++ 3,4장 예외, 효율 스터디
모어이펙티브 C++ 3,4장 예외, 효율 스터디모어이펙티브 C++ 3,4장 예외, 효율 스터디
모어이펙티브 C++ 3,4장 예외, 효율 스터디
 
Effective C++ Chapter 3 Summary
Effective C++ Chapter 3 SummaryEffective C++ Chapter 3 Summary
Effective C++ Chapter 3 Summary
 
HolubOnPatterns/chapter3_3
HolubOnPatterns/chapter3_3HolubOnPatterns/chapter3_3
HolubOnPatterns/chapter3_3
 
Effective c++(chapter 5,6)
Effective c++(chapter 5,6)Effective c++(chapter 5,6)
Effective c++(chapter 5,6)
 
Tcpl 14장 예외처리
Tcpl 14장 예외처리Tcpl 14장 예외처리
Tcpl 14장 예외처리
 
HolubOnPatterns/chapter2_2
HolubOnPatterns/chapter2_2HolubOnPatterns/chapter2_2
HolubOnPatterns/chapter2_2
 
Windows via c++ part 1
Windows via c++ part 1Windows via c++ part 1
Windows via c++ part 1
 
04 안드로이드 응용프로그램의 구조
04 안드로이드 응용프로그램의 구조04 안드로이드 응용프로그램의 구조
04 안드로이드 응용프로그램의 구조
 
게임프로그래밍입문 7
게임프로그래밍입문 7게임프로그래밍입문 7
게임프로그래밍입문 7
 

Api design for c++ ch3 pattern

  • 2.  Pimpl 이디엄  싱글톤과 팩토리 메서드  프록시, 어댑터와 퍼사드  옵저버
  • 3.  내부의 구체적인 코드를 public 헤더 파일로 부터 완전히 숨김  기본적으로 private 멤버 변수와 함수를 .cpp 파일에 위치 시킴
  • 4. 공개 인터페이스 Public: Function1() Function2() Protected: Function3() Private: Impl* pImpl 내부 구현 Public: PrivateFuntion1() PrivateFunction2() PrivateData1 privateData2 pImpl 이디엄은 숨겨진 구현 클래스를 내부 포인터로 가리키는 공개 클래스를 말함
  • 5. // autotimer.h #ifdef WIN32 #include <windows.h> #else #include <sys/time.h> #endif #include <string> class AutoTimer { public: /// Create a new timer object with a human readable name explicit AutoTimer(const std::string &name); /// On destruction, the timer reports how long it was alive AutoTimer(); private: // Return how long the object has been alive double GetElapsed() const; std::string mName; #ifdef WIN32 DWORD mStartTime; #else struct timeval mStartTime; #endif
  • 6. // autotimer.h #include <string> class AutoTimer { public: explicit AutoTimer(const std::string &name); AutoTimer(); private: class Impl; Impl *mImpl; };
  • 7. #include "autotimer.h" #include <iostream> #if_WIN32 #include <windows.h> #else #include <sys/time.h> #endif class AutoTimer::Impl { public: double GetElapsed() const { #ifdef _WIN32 return (GetTickCount() - mStartTime) / 1e3; #else struct timeval end_time; gettimeofday(&end_time, NULL); double t1 = mStartTime.tv_usec / 1e6 + mStartTime.tv_sec; double t2 = end_time.tv_usec / 1e6 + end_time.tv_sec; return t2-t1; #endif } std::string mName; #ifdef _WIN32 DWORD mStartTime; #else struct timeval mStartTime; #endif
  • 8. AutoTimer::AutoTimer(const std::string &name) : mImpl(new AutoTimer::Impl()) { mImpl->mName name; #ifdef _WIN32 mImpl->mStartTime = GetTickCount(); #else gettimeofday(&mImpl->mStartTime, NULL); #endif } AutoTimer::AutoTimer() { std::cout << mImpl >mName << ": took " << mImpl >GetElapsed() << " secs" << std::endl; delete mImpl; mImpl = NULL; }
  • 9. AutoTimer::AutoTimer(const std::string &name) : mImpl(new AutoTimer::Impl()) { mImpl->mName name; #ifdef _WIN32 mImpl->mStartTime = GetTickCount(); #else gettimeofday(&mImpl->mStartTime, NULL); #endif } AutoTimer::AutoTimer() { std::cout << mImpl >mName << ": took " << mImpl >GetElapsed() << " secs" << std::endl; delete mImpl; mImpl = NULL; }
  • 10. 1. Private 멤버 변수만을 포함한다. 2. Private 멤버 변수와 함수를 포함한다. 3. Public 클래스의 모든 함수와 대응되는 함수 를 Impl 클래스에 구현한다.
  • 11.  기본적으로 얕은 복사가 사용됨.  다음의 2가지 선택사항을 취해 얕은 복사 시 예상치 못한 오류 발생 예방  클래스를 복사할 수 없게 만듦 ▪ Private으로 복사 생성자 선언 및 할당 연산자 선언  깊은 복사 기능을 명시적으로 정의
  • 12.  정보 은닉  #define prive public  #include “yourapi.h”  #undef private  의존성 제거  Windows.h 및 sys/time.h에 대한 의존성 없앰  빠른 컴파일  Api 계층 구조가 줄어듦  뛰어난 이진 호환성  Pimpl 이디엄 포함한 객체의 크기는 절대 바뀌지 않음  지연 할당  Pimpl 클래스는 필요할 때 생성되기 때문에 네트워크 연결과 같은 제한된 또는 많은 비용이 드는 리소스를 사용할 때 유용
  • 13.  Pimpl 구현 객체를 메모리에 할당하고 해제해야하는 문제.  포인터의 크기 때문에 객체 크기 역시 늘어나서 모든 변수 접근에 필요한 간접 참조의 성능 문제 발생  New와 delete 호출에 따른 추가적인 비용 ▪ 빠른 Pimpl 이디엄(new와 delete 연산자를 오버로드 해서 적은 메모리를 사 용하도록 고정된 크기의 메모리 할당자를 사용하는 효율적인 메모리 사용 방 법)  코드를 읽는 것, 디버깅 하는것도 어려워 짐.  상수 함수 안에 있는 변수들은 분리된 객체 안에 존재하기 때문에 컴파일러는 이 변수들의 값 변화를 더 이상 감지할 수없음. void PimpledObject::ConstMethod() const { mImpl->mName = "string changed by a const method"; }
  • 14.  페이지 112 ~ 114 참고
  • 15.  어떻게 싱글톤 객체를 할당할 것인가?  언제 싱글톤 객체를 파괴 시킬 것인가?  쓰레드 안정성을 지원하는 가?  쭉정이(알맹이가 없는) 싱글턴을 사용하면 어떻게 되는가?
  • 16.  발전된 형태의 전역 변수  프로그램 상에서 하나의 인스턴스만 있고 두번째 인스턴스를 만들 수 없는 기능  쓰임에 따라 최선의 방법들이 달라짐
  • 17.  기본 생성자를 private에 선언  외부에서 new로 객체 생성 불가  Singleton* pObject = new Singleton();  컴파일 에러  복사 생성자, 복사 대입연산자 도 private에 선언  복사로 인한 생성 불가  정의를 하지 않고 선언만 함 (정의가 있으면 멤버함수 혹은 프렌드 함수가 호출 할 수 있기 때문에 정의 하지 않음)  복사 생성자 ▪ Singleton object1( Singleton::GetInstance() );  컴파일 에러  복사 대입 연산자 ▪ Singleton& object1 = Singleton::GetInstance(); ▪ Singleton& object2 = Singleton::GetInstance(); ▪ object1 = object2;  컴파일 에러
  • 19.  Static 클래스 멤버 변수는 static 전역 변수처럼 프로그램 시작 시 main() 함수 호출 이전에 초기화  싱글톤 객체 사용하지 않더라도 무조건 생성되기 때문 에 비효율적  정적 객체는 다른 전역객체의 생성자에서 참고하고 싶 은 경우 문제 발생 할 수 있음  C++ 표준에서는 전역 객체들의 생성 순서에 대해 명확하게 정 의하고 있지 않기 때문  Main() 함수가 실행 하기 전에만 생성되면 됨  어떤 전역 객체의 생성자에서 위 싱글톤 객체를 참조하려고 할 경우 싱글톤 객체가 생성되기 전인 경우 문제 발생 할 수 있 음
  • 21.  최초 GetInstace() 를 호출하는 시점에 객체가 생성  한번도 해당 객체를 생성하지 않으면 객체 생 성 하지 않으므로 자원을 효율적으로 사용  다른 전역 객체의 생성자에서 참조하는 것도 가능  프로그램이 종료되는 순간 동적 객체는 자동으 로 해제되기 때문에 굳이 명시적으로 해제할 필요 없음
  • 22.  프로그램을 종료하기 위해 exit() 가 수행하는 cleanup 과정 (C++ 기준) 1. 현재 thread의 thread storage duration 내에 있는 object 들을 모두 소멸 ( C++11 only) 2. static storage duration의 object들을 소멸 1. Static storage duration 2. Thread storage duration 3. Automatic storage duration 4. Dynamic storage duration 3. atexit 에 등록되어 있는 함수들을 호출 4. 모든 C stream(stdin, stdout, stderr 등등) 과 tmpfile 에 의해 생성된 파일들을 비우고 닫음 5. 제어권이 host environment 로 넘어감
  • 23.  두번째 싱글톤 객체가 반드시 프로그램 종료 시 반납해야 하는 외부 시스템 자원을 사용하 는 경우 사용  싱글턴 객체를 이용하여, OS 리소스 를 만들고 해제 하지 않는다면 "리소스 릭:Resource Leak" 이 발생  싱글턴 객체의 소멸자에 리소스 해제 기능을 놓고, 싱글턴 객체를 파괴 함 으로써 이러한 문제 해결  Ateexit() 함수를 사용  다른 전역 객체의 소멸자를 이용
  • 24.  #include <stdlib.h>  int atexit(void (*func)(void));  함수 호출 성공 시 0, 실패 시 0 아닌 값 반환.  반환형과 매개변수 형이 void로 선언된 함수의 이름이(주소 값이) atexit함수의 인자로 전달  인자로 전달된 함수가 프로그램 종료 시 자동으로 호출되며, 이렇게 자 동으로 호출되어야 할 함수는 32개 이상 등록할 수 있음.  atexit 함수의 특성  등록된 순서의 역순으로 호출  atexit 함수를 통해서 등록된 함수는 프로그램이 정상적으로 종료될 때에만 호출
  • 27.  명시적 해제 작업을 피하기 위해 static 지역 객 체 사용 1. 지역 static 객체는 전역 static 객체와 달리 해당 함수를 처음 호출 하는 시점에 초기화 2. 위 객체를 한번도 사용하지 않으면 생성되지 않음 3. Static 이므로 프로그램 종료 시 까지 객체가 유지 4. 종료시에는 자동으로 소멸자 호출
  • 28.  로그 객체, 키보드 객체, 모니터 객체가 존재하며, 네번째 싱글톤으로 구성 (1)키보드 객체를 생성하고, 모니터 객체를 생성 하는 중 실패하여, (2)로그 객체를 생성하여 로그를 찍음 (3)그리고 프로그램이 종료 작업에 들어 가게 됨.  에러 상황 (4) 로그 객체는 먼저 삭제됨. (5)키보드 객체를 파괴할 때, 실패하여, (6)로그 객체를 이용해 로그를 찍으려 함 하지만, 로그 객체는 이미 파괴된 후이므로, 쭉정이 싱글톤에 접근하게 되어, 크래 쉬가 발생  상황 분석  static 을 이용하기 때문에, 스택 형태로 메모리에 올라와져 있어, 키보드 객체가 파괴되기 전 로 그 객체 부터 파괴.  왜냐하면 로그 객체가 키보드 객체 후에 만들어졌기 때문
  • 29.  네번째 싱글톤 객체를 다른 전역 객체의 소멸 자에서 사용하려고 하면 문제 발생  C++ 표준에서는 전역 객체들의 생성 순서만 명시하 지 않은 것이 아니라 소멸 순서에 대해서도 명시해 놓지 않음  어떤 전역 객체가 소멸자에서 저 싱글톤 객체를 사 용하려고 할 때 싱글톤 객체가 먼저 소멸했다면 문 제가 발생 (참조 무효화)
  • 30.  싱글톤 참조 시 해당 객체의 소멸 여부를 파악 하고 만약 소멸했다면 되살림  싱글턴의 파괴 시점을 조작
  • 31.  Static 지역 변수의 특징  메모리의 생성은 프로그램이 static 지역변수 가 포함된 함수를 호출해야 생성  프로그램 종료 시점에 메모리 파괴가 일어난다 해도 그 공간은 빈 공간으로 남아 있음( 다른것으로 채워지지 않음)  위 특징 사용.  프로그램 종료 시점에 그 메모리 공간에 다시 쓰기 위 해 replacement new를 사용  파괴 시점을 제어하기 위해 std::atexit함수 사용
  • 32.  Replacement new  이미 할당된 메모리 공간에 생성자만 호출  일반 new처럼 사용하되 인자로 메모리가 할당되어있는 포인터를 넘겨줌  내부적으로 void* operator new(size_t, void*) 원형의 new를 호출  Ex)  void* pBase = malloc(sizeof(CBase));  new(pBase) CBase;  메모리를 재할당 하지 않음  기존 데이터가 그대로 남아있고, 생성자에서 초기화하는 데이터 만 초기화  가상함수 테이블을 초기화  메모리풀링 등에서 유용하게 사용
  • 34.  .cpp Static 객체의 생성/소멸 시점에 대해 정확히 파악해서 싱글톤 객체를 전 역 객체의 생성/ 소멸자에서 마구잡이로 참조하는 일이 없도록 주의해서 프로그래밍 해야함
  • 35.  고려해야 할 사항  싱글턴 객체의 생성 동기화
  • 36.  고려해야 할 사항  싱글턴 객체의 생성 동기화
  • 37.  멀티 스레드 환경 지원 안함
  • 38.  쓰레드A가 GetInstance() 함수 진입  1번 조건 체크 하고 다음 줄 실행 전에 중지  쓰레드 B가 GetInstance() 함수에 진입  쓰레드 B는 s_pInstance가 NULL 이므로 1번 계속 진행.   쓰레드 B는 2번 실행하여 객체 생성 후 호출자에게 instance 리턴  쓰레드A는 다시 진행 됨. 2번이 다시 호출되어 또다른 인스턴스 생성 A쓰레드 B쓰레드 2번 1번 2번 1번
  • 40. 널일 경우에만 락을 획득 하기 위함 위 조건 체크와 락을 얻을 때 사이에 다른 스 레드가 먼저 들어와서 pInstance를 초기화 할 수 있기 때문에 한번더 null 인지 체크
  • 41.  s_pInstance = new LazySingleton(); 의미  1. Singleton 객체를 담기 위한 메모리를 할당  2. 할당된 메모리에 Singleton 객체를 생성  3. s_pInstance가 할당된 메모리를 가리키도록 함  컴파일러가 이 순서대로 수행되도록 제한하지 않음. 컴파일러는 때때로 스텝 2와 스텝 3사이의 순서를 바꾸기도 함
  • 42.  A쓰레드에서 s_pInstance가 할당된 메모리 를 가리키도록 하고 그 후에 할당된 메모리 에 객체를 생성 해야 하는데 할당 전에  B 쓰레드에서 싱글턴 객체를 바로 사용할 경 우 껍데기를 접근하여 문제 발생  (싱글턴 객체는 메모리를 가리키기만 하고 실제 객체객체 생성은 안된 상황)
  • 43.  Volatile 한정 지시자 사용
  • 44.  volatile로 선언된 개체(변수, 메모리 위치, 코드)는 optimize 룰을 적용하지 말라.  ( Objects declared as volatile are not used in certain optimizations ( 출처 - MSDN ))  컴파일러가 효율 등을 고려해 optimize 관점에서 코 드를 임의로 변경(의미 없는 코드 삭제나 실행 순서 변경)을 시키지 않음  volatile로 선언된 개체는 메모리에 할당되고 작업 요 청시 직접(해당 주소에), 바로(효율을 위한 지연 없 이) 처리된다.
  • 45.  volatile 키워드를 사용해야 할 곳이 있다면 C++11에 서는 atomic 변수를 사용  C++11에서는 '서로 다른 스레드 간에 순서 관계가 정 의 되지 않은 메모리 읽기 쓰기 조작은 data race에 의한 알 수 없는 동작을 한다' 라고 되어 있음.  즉 C++11에서 volatile 변수는 Memory Barrier 동작을 한다고 명시하지 않음  메모리 바리어는 대부분 낮은 수준의 기계어에서 사 용되며 여러 장치가 공유하는 메모리를 사용하는 데 쓰임
  • 46.
  • 47.  Lazy Instance 모델 대신 코드가 실행되는 시점, main() 이 호출되기 전이나 뮤텍스 잠금으로 API가 초기화 시점에 초기화  정적 초기화 static Singleton& foo = Singleton::GetInstance();  명시적 API 초기화 Void APIInitialize() { Mutex mutex; ScopredLock(&mutex); Singleton::GetInstance(); }
  • 48.  의존성 삽입 class MyClass { public: MyClass() : mDatabase( new Database ("mydb, "localhost", "user", "pass")) {} private: Database* mDatabase; } class MyClass { public: MyClass(Database* db) : mDatabase(db) {} private: Database* mDatabase; }
  • 49.  모노스테이트 패턴  싱글톤의 문제는 전역 상태를 유지하고 접근하는데서 발생 // monostate.h class MonoState { public: int GetTheAnswer() const { return sAnswer; } private: static int sAnswer; }; // monostate.cpp int MonoState::sAnswer = 42;  세션 문맥 사용
  • 50.  C++ 생성자에서의 제약 사항  결과 값 리턴 불가  명명 규칙의 제약  정적 형식의 객체 생성  가상 생성자의 부재  팩토리 메서드는 위 제약사항에 구애받지 않음
  • 51. // renderer.h #include <string> class IRenderer { public: virtual IRenderer() {} virtual bool LoadScene(const std::string &filename) 0; virtual void SetViewportSize(int w, int h) 0; virtual void SetCameraPosition(double x, double y, double z) 0; virtual void SetLookAt(double x, double y, double z) 0; virtual void Render() 0; };
  • 52. // rendererfactory.h #include "renderer.h" #include <string> class RendererFactory { public: IRenderer *CreateRenderer(const std::string &type); }; // rendererfactory.cpp #include "rendererfactory.h" #include "openglrenderer.h" #include "directxrenderer.h" #include "mesarenderer.h“ IRenderer *RendererFactory::CreateRenderer(const std::string &type) { if (type "opengl") return new OpenGLRenderer(); if (type "directx") return new DirectXRenderer(); if (type "mesa") return new MesaRenderer(); return NULL;
  • 53.  사용자가 원하는 타입의 인스턴스를 런타임 시에 생성하기 때문에 유연성 제공  상속 클래스의 헤더 파일은 팩토리를 구현 하는 .cpp 파일에만 존재하며 public으로 선 언된 RenererFacory.h 파일에는 포함하지 않 음  그러나 이것은 사용자에게 새로운 그래픽 처리기를 제공하지 못함.
  • 54.  팩토리 메서드와 상속 클래스간의 연결 관 계를 느슨하게 만듦  런타임시에 새로운 상속 클래스를 추가할 수 있도록 타입 이름을 객체 생성 콜백 함수 에 연결시키는 맵을 팩토리 클래스에서 사 용
  • 55. // rendererfactory.h #include "renderer.h" #include <string> #include <map> class RendererFactory { public: typedef IRenderer *(*CreateCallback)(); static void RegisterRenderer(const std::string &type, CreateCallback cb); static void UnregisterRenderer(const std::string &type); static IRenderer *CreateRenderer(const std::string &type); private: typedef std::map<std::string, CreateCallback> CallbackMap; static CallbackMap mRenderers; };
  • 56. #include "rendererfactory.h" // instantiate the static variable in RendererFactory RendererFactory::CallbackMap RendererFactory::mRenderers; void RendererFactory::RegisterRenderer(const std::string &type, CreateCallback cb) { mRenderers[type] cb; } void RendererFactory::UnregisterRenderer(const std::string &type) { mRenderers.erase(type); } IRenderer *RendererFactory::CreateRenderer(const std::string &type) { CallbackMap::iterator it mRenderers.find(type); if (it ! mRenderers.end()) { // call the creation callback to construct this derived type return (it >second)(); } return NULL; }
  • 57. class UserRenderer : public IRenderer { public: UserRenderer() {} bool LoadScene(const std::string &filename) { return true; } void SetViewportSize(int w, int h) {} void SetCameraPosition(double x, double y, double z) {} void SetLookAt(double x, double y, double z) {} void Render() { std::cout << "User Render" << std::endl; } static IRenderer *Create() { return new UserRenderer(); } }; int main(int, char **) { // register a new renderer RendererFactory::RegisterRenderer("user", UserRenderer::Create); // create an instance of our new renderer IRenderer *r RendererFactory::CreateRenderer("user"); r->Render(); delete r; return 0; }
  • 58.  한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환 어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해 서 쓸 수 있음.
  • 59. public class Adapter implements target{ request(){ translatedRequest(); } } 클라이언트와 어댑티는 서로 분리 서로 상대방에 대해서 전혀 모름.
  • 60. 어댑터에서 타겟 인터페이스를 구현 어댑터는 어댑티로 구성 모든 요청은 어댑티에게 위임 public class Adapter implements target{ request(){ specificRequest(); } } 객체 구성(Composition) 사용 어댑티의 어떤 서브클래스에 대해서도 어댑터 를 쓸 수 있다는 장점 클라이언트를 특정 구현이 아닌 인터페이스에 연결 - 여러 어댑터 사용 가능 - 타겟 인터페이스만 제대로 지키다면 다른 구현 추가 가능
  • 61. 다중상속을 사용해서 어댑 터를 어댑티와 타켓 클랙스 모두의 서브클래스로 만듦. ※ 자바에서는 실제로 동작하지 않는 코드입니다 public class Adapter extends Target, Adaptee{ public void request(){ specificRequest(); } }
  • 62. - 어댑티 전체는 다시 구현하지 않아도 됨 - 어댑티의 행동을 오버라이딩 가능 - 구성을 사용하기 때문에 그 서 브클래스에 대해서도 어댑터 역할을 할 수 있음
  • 63.  어떤 서브시스템의 일련의 인터페이스에 대한 통합된 인터페이스를 제공 퍼사드에서 고수준 인터페이스를 정의하기 때문에 서브시스템을 더 쉽게 사용할 수 있 음
  • 64. 클래스 다이어그램 1. 일대다 관계 (one-to-many) • 상태를 저장하고 지배하는 것은 주제 객체. • 옵저버는 여러 개가 있을 수 있지만, 주제 객체에서 상태가 바뀌었다는 것을 알려주기 를 기다리는 주제에 의존 적인 성질을 가짐. 2. 의존성 1. 옵저버는 주제 객체가 데이터를 갱신해 주기를 기다리는 입장 이기 때문에 의존성을 가짐. 2. 이런 방식으로 인해 깔끔한 객체지향 디자인을 만들 수 있음. update() <interface> Observer regosterObserver() { … } removeObserver() { … } notifyObservers() { … } getState( ) setState( ) ConcreateSubject regosterObserver() removeObserver() notifyObservers() <interface> Subject update() //기타 해당 옵저버의 메소 드 ConcreateObserver 옵저버 주제 옵저버가 될 가능성 이 있는 객체는 해당 인터페이스 상속. 옵저버를 등록/탈퇴/공지 하는 기능 상태를 설정하는 메소드가 필요 • 옵저버 패턴 한 객체의 상태가 바뀌면 그 객체 에 의존하는 다른 객체들한테 연락 이 가고 자동으로 내용이 갱신되는 방식으로 일대다(one-to-many) 의 존성을 정의
  • 65.  옵저버 패턴에서는 주제와 옵저버가 느슨하게 결합되어 있는 객체 디자인을 제공.  주제가 옵저버에 대해 아는 것은 옵저버가 특정 인터페이스를 구현(implements) 한다는 것 뿐.  옵저버는 언제든지 새로 추가할 수 있음  새로운 형식의 옵저버를 추가하려고 할 때도 주제를 전혀 변경 할 필요가 없음.  주제와 옵저버는 서로 독립적으로 재사용할 수 있음.  주제나 옵저버가 바뀌더라도 서로한테 영향을 미치지 않음.

Editor's Notes

  1. 플랫폼 종속적인 정의 포함 모든 이가 볼 수 있는 헤더파일에 타이머가 어떤 형태로 다른 플랫폼에 저장된는지 구체적인 내용들을 노출
  2. Private 클래스로 선언 AutoTime 클래스의 메서드만이 Impl 클래스의 멤버에 접근 할 수 있다는 제약 조건 Cpp 파일에 정의된 다른 클래스 또는 함수가 Iimpl클래스의 멤버에 접근하고자 할 경우 public으로 Impl을 선언 후 접근
  3. Pimpl이 불편하면서 쉽게 오류를 발생시키는 이유는 객체의 메모리 할당과 해제가 필요하기 때문 Shared_ptr 사용해서 할당과 해제 신경 쓰지 않도록 함. 혹은 scoped_ptr을 사용. 이것은 복사가 불가능하며 이것을 사용하면 private 복사 생성자 및 할당 연산자를 선언하지 않아도 되기 때문.
  4. 보편적으로 2번을 사용하여 모두 포함하길 권장.
  5. 메모리릭 문제는 지속적으로 메모리 할당이 일어나는데 해제는 안되는 상황에서 발생하는 문제이지 이 객체 처럼 한번만 생성되어 프로그램 종료 시 까지 유지되는 객체는 문제가 되지 않음
  6. static storage duration 함수 정의의 바깥에서 정의된 변수 또는 키워드 static을 사용하여 정의된 변수 Automatic storage duration 함수 매개변수를 포함한 함수 정의 안에 선언된 변수. 그들은 함수나 블록안으로 들어갈 떄 생성되어 나올때 해제 dynamic storage duration new 연산자를 사용하여 할당된 메모리는 delete 연산자로 해제되거나 프로그램이 종료 될 때까지 존속
  7. 쓰레드가 동시에 싱글턴 객체를 생성할 경우, 마지막에 생성된 싱글턴 객체만 정상적으로 사용할 수 있고, 그 전에 생성된 객체는 사용할 수 있게 되므로, 싱글턴 객체를 생성할 때, 쓰레드에 안전하도록 유의
  8. 쓰레드가 동시에 싱글턴 객체를 생성할 경우, 마지막에 생성된 싱글턴 객체만 정상적으로 사용할 수 있고, 그 전에 생성된 객체는 사용할 수 있게 되므로, 싱글턴 객체를 생성할 때, 쓰레드에 안전하도록 유의
  9. 쓰레드가 동시에 싱글턴 객체를 생성할 경우, 마지막에 생성된 싱글턴 객체만 정상적으로 사용할 수 있고, 그 전에 생성된 객체는 사용할 수 있게 되므로, 싱글턴 객체를 생성할 때, 쓰레드에 안전하도록 유의
  10. 쓰레드가 동시에 싱글턴 객체를 생성할 경우, 마지막에 생성된 싱글턴 객체만 정상적으로 사용할 수 있고, 그 전에 생성된 객체는 사용할 수 있게 되므로, 싱글턴 객체를 생성할 때, 쓰레드에 안전하도록 유의
  11. 호출 할 때마다 항상 락이 걸리기 때문에 성능 문제 발생
  12. Irenderer 클래스를 상속받은 OpenglRenderer, DirectxRenderer, MesaRenderer 세개의 클래스를 구현했다고 가정
  13. 주의 사항 : Create() 함수를 UserRenderer 클래스에 추가한 부분 팩토리의 RegisterRenderer 함수는 객체를 하나 리턴하는 콜백 함수를 취하는데 이 콜백 함수는 Irenderer 클래스의 멤버가 되어서는 안되기 때문에 static으로 선언.