import os
import subprocess
def ExecuteCmd(self, strCmd):
print "[ExecuteCmd] %s" % (strCmd)
pipe = subprocess.Popen(strCmd,
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
pipe.stdin.close()
retOutputList = []
while( pipe.poll() is None ):
out = pipe.stdout.readline()
if( out != '' ):
print out
retOutputList.append(out)
retCode = pipe.poll()
return (retCode, retOutputList)
def main():
(retCode, stdout) = ExecuteCmd('svn --version')
print 'retCode : ' + str(retCode)
print stdout
if __name__ == "__main__":
try:
main()
except os.error, err:
print str(err)
글 검색 결과
- 2012/01/19 [Python] ExecuteCmd 커맨드 명령어 실행하기
- 2011/08/03 MMORPG에서 좁은 지역에 유저 N명이 모여 있을 때 처리 방법
- 2011/07/28 std::for_each와 Concurrency::parallel_for_each의 속도 비교
- 2011/06/30 추상 팩토리(AbstractFactory) 패턴
- 2011/06/14 JIRA 이슈 트래커 설치하기
- 2011/06/11 Boost Graph Library(BGL)를 이용한 Dijkstra's shortest path (6)
- 2011/03/29 [NSIS] 서버 프로그램 빌드 스크립트 예제
- 2011/02/07 std::numeric_limits 관련 에러가 발생할때 대처 방법
- 2011/01/23 [VA Snippet] class with prompt for name
- 2011/01/23 [VA Snippet] Set, Get Method
- 2011/01/06 functor 관련 snippet
- 2010/11/08 [Python] 루아 스크립트 주석 '--' 왼쪽 문자열 추출 함수 (1)
- 2010/11/08 [Python] 문자열에서 '=' 오른쪽 왼쪽 문자열 추출 함수
- 2010/11/08 [Python] 문자열에서 영문+숫자+언더바 추출 함수
- 2010/10/10 [STL] std::copy_if, std::remove_copy_if (4)
[Python] ExecuteCmd 커맨드 명령어 실행하기
Python에서 Command 명령어 실행하는 예제
- 이 글의 트랙백 주소
- 이 글에는 트랙백을 보낼 수 없습니다
add
- 댓글 남기기
MMORPG에서 좁은 지역에 유저 N명이 모여 있을 때 처리 방법
MMORPG에서 좁은 지역에 유저가 N명이
모여 있을 때 처리 방법
(출처 : http:://www.npteam.net/855)
1. 기획적 의도로 해결하는 방법
- 국지전이 일어나는 장소를 여러 곳으로 분할한다.
- 국지전에 참여할 수 있는 최대 인원수를 제한한다.
2. 프로그램적으로 해결하는 방법
- 영향을
미치는 요소들
- 데이터 크기
- 데이터를 보내는 빈도 수
- 전송 특성
- 1:1 패킷 보내기
- 1:N 패킷 보내기
- N:M 패킷 보내기
- 해결방법
- 데이터 크기
- 패킷 데이터의 크기를
최대한 줄인다.
- 패킷에 포함된 기본
정보 단위를 최소화 한다.
( 자료형 단위를 줄이는 방법, 불필요한 정보를 제거하는 방법 ) - 패킷 데이터를 압축한다.
- 패킷 데이터를 압축/해제시 CPU 자원을 사용한다.
- 브로드캐스팅할 경우
패킷이 작아지면 트래픽이 줄어드는 잇점이 있다.
- 데이터를 보내는 빈도 수
- 최대 빈도수를 정한다.
- 클라이언트 응답 속도 250ms일 경우 1초에 4번
- 클라이언트 응답 속도 200ms일 경우 1초에 5번
(이동 패킷과 스킬 사용 패킷을 1초에 4-5번으로 해결하기 어렵다.) - 우선순위 큐를 이용한
패킷 전송
- 전투 관련 패킷을 우선적으로
처리한다.
- 비우선 패킷들 : 로그, 채팅, 환경
오브젝트 처리
- 이미 전송한 명령은 Send 버퍼 Queue에서 삭제한다.
- 동일한 좌표로 계속
이동하는 패킷은 클라이언트에서 한번만 보내도 된다.
- 필요 없는 패킷을 제거하여, 트래픽도 줄이고 서버의 CPU 자원 사용도 줄일 수
있다.
- 전송 특성
- 1:1 패킷 보내기
- 문제점 없음
- 1:N 패킷 보내기
- Send 패킷 버퍼 재활용 필요함.
- N:M 패킷 보내기
- 패킷 압축 필요함.
- Send 패킷 버퍼 재활용 필요함.
- 브로드캐스팅을 게임
서버에서 하지 않고, Front 혹은 Agent 서버로
패스하여 처리한다.
(UDP SuperPeer를 사용할 경우 클라이언트에서 브로드 캐스팅하는 것도 고려해 볼 수 있다.)
3. 그외에 더 생각해 볼 사항
- CPU
자원
- 메모리간 데이터 복사를
최소화 한다.
- C++0x의 std::move를 사용하여 데이터 값 복사를 줄인다.
- Reference
Count 기능을
가진 패킷 컨테이너를 사용한다.
- 메모리간 데이터 복사를
빠르게 한다.
- FastMemcpy와 같이 CPU의 기본 레지스터 이외의 MMX와 같은 크기가 큰
레지스터에 데이터를 unrolling 하여,
Loop를 이용한 데이터 복사 속도 저하를 개선한다.
- 네트워크
자원
- 보장이 필요한 패킷과 보장이
필요 없는 패킷으로 구분하여 처리한다.
- 보장이 필요한 패킷 : 주기적인 시간 간격으로 동기화에 필요한 중요한 정보
예) X, Y, Z, 좌표 + Angle - 보장이 필요 없는 패킷 : 주기적인 시간 간격보다 짧은 간격이면서, 손실되어도
문제 없는 정보
예) Angle 정보 - 보장이 필요한 패킷은 TCP로 보내고, 보장이 필요 없는 패킷은 UDP로 나누어 처리할 수 있다.
(단, 중국의 경우 UDP가 불가능한 상황도 발생한다.)
- 브로드
캐스팅을 주체하는 서버를 구분한다.
- Game 서버가 모든 패킷을 브로드캐스팅
하면, Front 혹은 Agent 서버에 N번의 요청을 전달한다.
- 브로드캐스팅이 필요한 패킷을
각 Front 혹은 Agent 서버에 1회만 보내고(받을 클라이언트 목록을 함께), Front 혹은 Agent 서버에서 처리한다면,
Game 서버에서 N번 요청에 대한 CPU 자원 사용을 줄이고, 내부 네트워크 트래픽도 감소한다.
- 유저
상태에 대한 패킷 처리
- 유저가 전투 상태일 경우
패킷을 먼저 처리하고,
비 전투 상태일 경우 나중에 처리하도록 한다.
예) 마을에 모인 유저인 경우, 패킷이 늦게 처리되어도 문제가 발생하지 않는다.
- 이 글의 트랙백 주소
- 이 글에는 트랙백을 보낼 수 없습니다
add
- 댓글 남기기
std::for_each와 Concurrency::parallel_for_each의 속도 비교
std:for_each와 Concurrency::parallel_for_each 중에 어떤것이 더 빠른 속도를 낼 것인가?
가정 1. CPU Core가 늘어남에 따라 Single Thread보다는 Multi Thread를 활용하여 CPU 자원을 최대한 활용한다.
가정 2. 컨테이너를 읽기 전용으로 접근할 경우 Lock 객체를 사용하지 않아도 된다.
그러나 위 4가지 가정에서 예측한 것과 다른 값이 도출되었다.
가정 1. CPU Core가 늘어남에 따라 Single Thread보다는 Multi Thread를 활용하여 CPU 자원을 최대한 활용한다.
가정 2. 컨테이너를 읽기 전용으로 접근할 경우 Lock 객체를 사용하지 않아도 된다.
(Race Condition, 스레드간 공유 자원 접근 문제)
가정 3. Thread 갯수가 과도하게 늘어나서 빈번하게 Context Switching이 발생할 경우 속도 저하가 발생한다.
가정 3. Thread 갯수가 과도하게 늘어나서 빈번하게 Context Switching이 발생할 경우 속도 저하가 발생한다.
(Concurrency::parallel_for_each는 Thread 갯수를 스스로 조절한다.)
가정 4. 암달의 법칙(Amdahl's law)으로 직렬화된 작업을 병렬화 작업으로 바꾸더라도 속도 향상에는 한계가 있을 것이다.
위 4가지 가정으로 봤을때, 컨테이너를 이터레이팅 할때 많은 도움은 안되더라도 약간의 속도 향상을 기대하였다.
가정 4. 암달의 법칙(Amdahl's law)으로 직렬화된 작업을 병렬화 작업으로 바꾸더라도 속도 향상에는 한계가 있을 것이다.
위 4가지 가정으로 봤을때, 컨테이너를 이터레이팅 할때 많은 도움은 안되더라도 약간의 속도 향상을 기대하였다.
int _tmain(int argc, _TCHAR* argv[])
{
setlocale( LC_ALL, "Korean" );
std::vector< int > vecContainer;
for( int i = 0; i < 10000; ++i )
{
vecContainer.push_back( i );
}
class fntorPrintElem : public std::unary_function< int, void >
{
public:
explicit fntorPrintElem() {};
void operator() ( const int& elem ) const
{
std::wcout << "";
}
};
// std::for_each 속도 체크 코드 생략...
std::for_each( vecContainer.begin(), vecContainer.end(), fntorPrintElem() );
// Concurrency::parallel_for_each 속도 체크 코드 생략...
Concurrency::parallel_for_each( vecContainer.begin(), vecContainer.end(), fntorPrintElem() );
return 0;
}
그러나 위 4가지 가정에서 예측한 것과 다른 값이 도출되었다.
std::for_each 수행 시간 : 0.004950
Concurrency::parallel_for_each 수행시간 : 0.005819
parallel_for_each를 사용하면, std::for_each를 사용했을때 보다 오히려 성능이 떨어진다.
일반적인 상황에서 Concurrency::parallel_for_each를 사용했을 경우 성능 향상을 보장 받을 수 없다.
그렇다면 parallel_for_each가 더 빠르게 하려면 무엇을 해야 할까?
functor에서 Sleep(1)을 넣어서 측정한 결과는 다음과 같다.
Concurrency::parallel_for_each 수행시간 : 0.005819
parallel_for_each를 사용하면, std::for_each를 사용했을때 보다 오히려 성능이 떨어진다.
일반적인 상황에서 Concurrency::parallel_for_each를 사용했을 경우 성능 향상을 보장 받을 수 없다.
그렇다면 parallel_for_each가 더 빠르게 하려면 무엇을 해야 할까?
functor에서 Sleep(1)을 넣어서 측정한 결과는 다음과 같다.
std::for_each 수행 시간 : 10.019599
Concurrency::parallel_for_each 수행시간 : 3.753167
측정 결과 parallel_for_each가 std::for_each보다 상대적으로 약 2.6배 빠르지만,
std::for_each는 2504배 느려지고, parallel_for_each는 750배 느려졌다.
일반적인 컨테이너를 이터레이팅 하는 상황에서 Concurrency::parallel_for_each로 대체하기만 하면,
속도 향상이 있을 것이라는 기대는 깨졌지만,
네트워크 I/O와 같은 비동기 대기가 발생하는 상황에서
코딩 난이도가 높지 않은 parallel_for_each를 활용하면, 속도 향상에 도움이 될 것으로 예측한다.
Concurrency::parallel_for_each 수행시간 : 3.753167
측정 결과 parallel_for_each가 std::for_each보다 상대적으로 약 2.6배 빠르지만,
std::for_each는 2504배 느려지고, parallel_for_each는 750배 느려졌다.
일반적인 컨테이너를 이터레이팅 하는 상황에서 Concurrency::parallel_for_each로 대체하기만 하면,
속도 향상이 있을 것이라는 기대는 깨졌지만,
네트워크 I/O와 같은 비동기 대기가 발생하는 상황에서
코딩 난이도가 높지 않은 parallel_for_each를 활용하면, 속도 향상에 도움이 될 것으로 예측한다.
- 이 글의 트랙백 주소
- 이 글에는 트랙백을 보낼 수 없습니다
add
- 댓글 남기기
JIRA 이슈 트래커 설치하기
JIRA는 이슈(Issue)를 관리하는 웹 기반 소프트웨어 입니다.
JIRA를 설치하기 위해서 http://www.atlassian.com/software/jira/에서 JIRA를 다운로드 합니다.
처음 설치하실 때에는 다음 버튼을 눌러서 설치하시고,
이미 설치되어 있는 경우에는 다음 단계에서 주의 하셔야 합니다.
설치를 중지하고 데이터 백업이 올바르게 되었는지 다시 한번 확인합니다.
처음 설치하신다면 위 메시지 박스가 나오지 않습니다.
다음과 같이 진행됩니다.
서비스 모드로 설치할 경우에는 Local System 계정으로 실행됩니다.
잘 모르실 경우에는 다음을 누르시면 됩니다.
JIRA 제목을 입력하시고, 발급 받으신 라이센스 키를 입력합니다.
JIRA를 관리하는 관리자 계정 정보를 입력합니다.
이메일 알림을 받을지 설정하는 페이지 입니다.
알림을 받지 않으실 경우 Disable Email Notifications 버튼을 누르고 진행합니다.
이제 모든 설치가 끝났습니다.
- 이 글의 트랙백 주소
- 이 글에는 트랙백을 보낼 수 없습니다
add
- 댓글 남기기
Boost Graph Library(BGL)를 이용한 Dijkstra's shortest path
Boost Graph Library(BGL)은 Graph를 처리하는 범용 그래픽 라이브러리 입니다.
그래프(Graph)는 정점(vertex), 선(edge)으로 이루어져 있습니다.
1차원을 구성하는 점과 선이 기본 요소이기 때문에 1차원 이상의 고차원에 존재하는 모든 표현이 가능합니다.
그래프로 할 수 있는 일이 굉장히 많습니다.
- UML 다이어그램
- Node 기반 그래프(퀘스트 연결 관계 등..)
- C++ 헤더 파일 포함 관계 그래프
- 최단거리 길 찾기
- ...
이번에는 BGL을 이용하여 Dijkstra(다익스트라) 최단거리 알고리즘을 활용해 보겠습니다.
위와 같은 그래프를 BGL Dijkstra Shortest Path 알고리즘을 활용하여 처리한 결과는 다음과 같습니다.
#include "ShortestPath.h"
int _tmain(int argc, _TCHAR* argv[])
{
setlocale( LC_ALL, "Korean" );
CShortestPath ShortestPath;
ShortestPath.BuildGraph();
return 0;
}
main 함수에서 하는 일은 없습니다. CShortestPath 클래스가 핵심입니다.BuildGraph()에서 하는 일은 다음과 같습니다.
- Vertex 추가 / 이름 설정
- Edge 추가 / 이름 / 가중치 설정
- boost::dijkstra_shortest_paths()로 최단 거리 구하기
- PrintShortestPath( vStartVertex )에서 시작 vertex를 지정하고 최단거리 Console로 출력하기
- WriteGraphviz()에서 Graphviz.dot 파일로 그래프 파일 출력하기
void CShortestPath::BuildGraph()
{
//////////////////////////////////////////////////////////////////////////
// Vertex 추가하기
const VertexDescriptor vA = boost::add_vertex( m_Graph );
const VertexDescriptor vB = boost::add_vertex( m_Graph );
const VertexDescriptor vC = boost::add_vertex( m_Graph );
const VertexDescriptor vD = boost::add_vertex( m_Graph );
const VertexDescriptor vE = boost::add_vertex( m_Graph );
// Vertex 이름 설정하기
boost::put( boost::vertex_name, m_Graph, vA, "A" );
boost::put( boost::vertex_name, m_Graph, vB, "B" );
boost::put( boost::vertex_name, m_Graph, vC, "C" );
boost::put( boost::vertex_name, m_Graph, vD, "D" );
boost::put( boost::vertex_name, m_Graph, vE, "E" );
//////////////////////////////////////////////////////////////////////////
// Edge 추가하기
const EdgeDescriptor eAC = boost::add_edge( vA, vC, m_Graph ).first;
const EdgeDescriptor eBB = boost::add_edge( vB, vB, m_Graph ).first;
const EdgeDescriptor eBD = boost::add_edge( vB, vD, m_Graph ).first;
const EdgeDescriptor eBE = boost::add_edge( vB, vE, m_Graph ).first;
const EdgeDescriptor eCB = boost::add_edge( vC, vB, m_Graph ).first;
const EdgeDescriptor eCD = boost::add_edge( vC, vD, m_Graph ).first;
const EdgeDescriptor eDE = boost::add_edge( vD, vE, m_Graph ).first;
const EdgeDescriptor eEB = boost::add_edge( vE, vB, m_Graph ).first;
const EdgeDescriptor eEA = boost::add_edge( vE, vA, m_Graph ).first;
// Edge 이름 설정하기
boost::put( boost::edge_name, m_Graph, eAC, "AC" );
boost::put( boost::edge_name, m_Graph, eBB, "BB" );
boost::put( boost::edge_name, m_Graph, eBD, "BD" );
boost::put( boost::edge_name, m_Graph, eBE, "BE" );
boost::put( boost::edge_name, m_Graph, eCB, "CB" );
boost::put( boost::edge_name, m_Graph, eCD, "CD" );
boost::put( boost::edge_name, m_Graph, eDE, "DE" );
boost::put( boost::edge_name, m_Graph, eEB, "EB" );
boost::put( boost::edge_name, m_Graph, eEA, "EA" );
// Edge에 가중치 설정하기
boost::put( boost::edge_weight, m_Graph, eAC, 1 );
boost::put( boost::edge_weight, m_Graph, eBB, 2 );
boost::put( boost::edge_weight, m_Graph, eBD, 1 );
boost::put( boost::edge_weight, m_Graph, eBE, 2 );
boost::put( boost::edge_weight, m_Graph, eCB, 7 );
boost::put( boost::edge_weight, m_Graph, eCD, 3 );
boost::put( boost::edge_weight, m_Graph, eDE, 1 );
boost::put( boost::edge_weight, m_Graph, eEB, 1 );
boost::put( boost::edge_weight, m_Graph, eEA, 1 );
//////////////////////////////////////////////////////////////////////////
// Shortest Path 구하기
// Property Map 가져오기
boost::property_map< Graph, boost::edge_weight_t >::type mapEdgeWeight = boost::get( boost::edge_weight, m_Graph );
boost::property_map< Graph, boost::vertex_index_t >::type mapVertexIndex = boost::get( boost::vertex_index, m_Graph );
boost::property_map< Graph, boost::vertex_distance_t >::type mapVertexDistance = boost::get( boost::vertex_distance, m_Graph );
boost::property_map< Graph, boost::vertex_predecessor_t >::type mapVertexPredecessor = boost::get( boost::vertex_predecessor, m_Graph );
// 다익스트라 최단거리 알고리즘
const VertexDescriptor vStartVertex = vA;
boost::dijkstra_shortest_paths(
m_Graph,
vStartVertex,
boost::weight_map( mapEdgeWeight ).vertex_index_map( mapVertexIndex ).distance_map( mapVertexDistance ).predecessor_map( mapVertexPredecessor )
);
//////////////////////////////////////////////////////////////////////////
// 최단거리 결과 출력
PrintShortestPath( vStartVertex );
// Dot 파일로 출력
WriteGraphviz();
}기존 BGL 책에 소개된 배열 기반의 예제를 탈피해서,
STL을 주로 사용하시는 분들에 맞게 코드를 작성하였습니다.
다른 기능을 추가하고자 하신다면, boost.org의 Graph 라이브러리 페이지를 참조하세요.
- 이 글의 트랙백 주소
- 이 글에는 트랙백을 보낼 수 없습니다
[NSIS] 서버 프로그램 빌드 스크립트 예제
!define SERVICE_TYPE "R_KOREA_SERVICE"
!define SERVICE_BINARYNAME "_R_KOREA_SERVICE"
!define PRODUCT_NAME "TTFServer - ${SERVICE_TYPE}"
!define PRODUCT_VERSION "${__DATE__} ${__TIME__}"
!define PRODUCT_PUBLISHER "www.npteam.net, Inc."
!define PRODUCT_WEB_SITE "http://www.npteam.net"
; MUI 1.67 compatible ------
!include "MUI.nsh"
; MUI Settings
!define MUI_ABORTWARNING
!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
; Welcome page
!insertmacro MUI_PAGE_WELCOME
; Directory page
!insertmacro MUI_PAGE_DIRECTORY
; Instfiles page
!insertmacro MUI_PAGE_INSTFILES
; Finish page
;!define MUI_FINISHPAGE_RUN "$INSTDIR\TTFServer${SERVICE_BINARYNAME}.exe"
!insertmacro MUI_PAGE_FINISH
; Language files
!insertmacro MUI_LANGUAGE "Korean"
; MUI end ------
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
OutFile "Installer\Server-${SERVICE_TYPE}.exe"
InstallDir "D:\TTFServer"
InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
ShowInstDetails show
Function .onInit
InitPluginsDir
; TTFServer_Process Find And Kill
TTFServer_Process:
Processes::FindProcess "TTFServer${SERVICE_BINARYNAME}"
${If} $R0 == "1"
MessageBox MB_YESNO|MB_ICONSTOP "TTFServer${SERVICE_BINARYNAME}가 실행중입니다. 종료하시겠습니까?" IDNO Final
Processes::KillProcess "TTFServer${SERVICE_BINARYNAME}"
${If} $R0 == "1"
Goto TTFServer_Process
${Else}
MessageBox MB_OK "TTFServer${SERVICE_BINARYNAME} 종료에 실패하였습니다. 설치를 중단합니다."
Abort
${EndIf}
${EndIf}
Final:
FunctionEnd
Section "ServerBin" SEC01
SetOutPath "$INSTDIR"
File "bin\TTFServer${SERVICE_BINARYNAME}.exe"
File "bin\TTFServer${SERVICE_BINARYNAME}.pdb"
RMDir /r "$INSTDIR\Data"
SetOutPath "$INSTDIR\Data"
File /r "bin\Data\"
SectionEnd
Section "Delete Extra Folder" SEC02
RMDir /r "$INSTDIR\Data\Extra"
CreateDirectory "$INSTDIR\Data\Extra"
SectionEnd
Section "Firewall Setting" SEC03
; TTFServer${SERVICE_BINARYNAME}.exe, RemoteIP - any
ExecWait 'netsh advfirewall firewall delete rule name="TTFServer${SERVICE_BINARYNAME}.exe"'
ExecWait 'netsh advfirewall firewall add rule name="TTFServer${SERVICE_BINARYNAME}.exe" program="$INSTDIR\TTFServer${SERVICE_BINARYNAME}.exe" protocol=TCP remoteip=any dir=in security=notrequired action=allow'
SectionEnd
Section "VS_RedistributePackage" SEC04
SetOutPath "$INSTDIR"
File "D:\VS2008\VS2008SP1_RedistributePackage\vcredist_x86.exe"
ExecWait "$INSTDIR\vcredist_x86.exe /q"
SectionEnd
Section -Post
SectionEnd
- 이 글의 트랙백 주소
- 이 글에는 트랙백을 보낼 수 없습니다
add
- 댓글 남기기
std::numeric_limits 관련 에러가 발생할때 대처 방법
std::numeric_limits는 Template Type을 체크하여 min, max 상수값을 알려주는 유용한 함수이다.
그러나 windows.h 헤더에 정의된
#define min(a, b)
#define max(a, b)
2가지 정의가 전처리기에서 우선으로 처리되기 때문에 컴파일 에러가 발생한다.
따라서 windows.h 헤더위에 #define NOMINMAX를 선언하여 매크로를 비활성화 시키는 방법을 사용한다.
위 내용이 포함된 링크를 추가한다.
- 이 글의 트랙백 주소
- 이 글에는 트랙백을 보낼 수 없습니다
add
- 댓글 남기기
functor 관련 snippet
functor 일반
class fntor$FUNCTOR_NAME$ : public std::unary_function< $ELEMENT_TYPE$, $RETURN_TYPE$ >
{
public:
explicit fntor$FUNCTOR_NAME$() {};
$RETURN_TYPE$ operator() ( const $ELEMENT_TYPE$& elem ) const
{
$end$
}
private:
};
functor this 포인터 포함class fntor$FUNCTOR_NAME$ : public std::unary_function< $ELEMENT_TYPE$, $RETURN_TYPE$ >
{
public:
explicit fntor$FUNCTOR_NAME$( $ClassName$* pThis )
: _pThis( pThis )
{};
$RETURN_TYPE$ operator() ( const $ELEMENT_TYPE$& elem ) const
{
$end$
}
private:
$ClassName$* _pThis;
};
-------------------------
- 이 글의 트랙백 주소
- 이 글에는 트랙백을 보낼 수 없습니다
add
- 댓글 남기기
[Python] 루아 스크립트 주석 '--' 왼쪽 문자열 추출 함수
def RemoveLuaComment( strLine ) : find_pos = strLine.find( '--', 0 ) if( find_pos != -1 ) : return strLine[0 : find_pos].strip() return strLine.strip()
- 이 글의 트랙백 주소
- 이 글에는 트랙백을 보낼 수 없습니다
[Python] 문자열에서 '=' 오른쪽 왼쪽 문자열 추출 함수
def LeftSideOfEqual( strLine ) : strLine = RemoveLuaComment( strLine ) find_pos = strLine.find( '=', 0 ) if( find_pos != -1 ) : return strLine[0 : find_pos].strip() return strLine.strip() def RightSideOfEqual( strLine ) : strLine = RemoveLuaComment( strLine ) find_pos = strLine.find( '=', 0 ) if( find_pos != -1 ) : return strLine[find_pos + 1 : len(strLine)].strip() return strLine.strip()
- 이 글의 트랙백 주소
- 이 글에는 트랙백을 보낼 수 없습니다
add
- 댓글 남기기
[Python] 문자열에서 영문+숫자+언더바 추출 함수
def Extract_Alparbet_Number_UnderBar( strLine ) : strAlparbet_Number_UnderBar = string.letters + string.digits + '_' strList = [] for OneWord in strLine : if( OneWord in strAlparbet_Number_UnderBar ) : strList.append( OneWord ) strTemp = ''.join( strList ) return strTemp
- 이 글의 트랙백 주소
- 이 글에는 트랙백을 보낼 수 없습니다
add
- 댓글 남기기
[STL] std::copy_if, std::remove_copy_if
STL 알고리즘에는 std::copy와 std::remove_copy가 정의되어 있습니다.
이름에서 추측할 수 있듯이 std::copy는 두 컨테이너간 element 복사를 합니다.
또한 std::remove_copy는 특정한 element를 제외하고 복사 합니다.
std::copy_if 는 STL 알고리즘에 포함되어 있지 않습니다.
그 대신 std::remove_copy_if 가 정의되어 있습니다.
왜 그럴까요?
C++ 표준화 위원회에서 살짝 빠트린(?) 걸까요?
그렇게 생각하기엔 뭔가 이상하다고 생각되시죠. 저도 그렇습니다. ㅎㅎ
그렇다면, std::remove_copy_if는 어떻게 생겼을까요?
template< class _InIt,
class _OutIt,
class _Pr > inline
_OutIt _Remove_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred, _Range_checked_iterator_tag)
{ // copy omitting each element satisfying _Pred
_DEBUG_RANGE(_First, _Last);
_DEBUG_POINTER(_Dest);
_DEBUG_POINTER(_Pred);
for (; _First != _Last; ++_First)
if (!_Pred(*_First))
*_Dest++ = *_First;
return (_Dest);
}
위와 같이 생겼습니다. 무슨 뜻인지 모르시겠다구요.딱! 보면...
저도 잘 모르겠습니다.(딱 봐서 알기엔 아직 실력이 부족해서요. ㅎㅎ)
아무래도 첫번째 컨테이너의 First Iterator에서 Last Iterator까지
반복문을 돌면서 조건식에 일치하지 않는 iterator만
두번째 컨테이너에 하나씩 element 복사를 하는 로직으로 보입니다.
헉. 조건에 일치하지 않는? 뭔가 이상하죠. ㅎㅎ
제거하면서 복사해야 하니까 조건에 일치하지 않는 것들만 복사하는게 맞는데요.
뭐가 이상하다는거죠?
눈치 빠르신 분은 느끼셨겠지만 조건에 일치하는 값만 복사하게 한다면?
조건에 일치하는 값만 복사하게 한다는 것은 결국 std::copy_if로 사용한다는 것입니다.
오호~ 그렇다면 조건에 일치하지 않는 것을 조건에 일치하게 만들어서 쓰면 된다는 것이군요.
그래서 아래와 같이 std::remove_copy_if를 -> std::copy_if 처럼 사용할 수 있습니다.
그 방법은 바로 조건문을 반전시키는 std::not1, std::not2 입니다.
std::vector< int > vecInteger; vecInteger.push_back( 1 ); vecInteger.push_back( 2 ); vecInteger.push_back( 3 ); vecInteger.push_back( 2 ); vecInteger.push_back( 5 ); std::vector< int > vecOutput; std::remove_copy_if( vecInteger.begin(), vecInteger.end(), std::back_inserter( vecOutput ), std::bind2nd( std::equal_to< int >(), 2 ) );이 결과는 이렇습니다.
그렇다면 아래와 같이 std::not1을 활용하면,
std::vector< int > vecInteger; vecInteger.push_back( 1 ); vecInteger.push_back( 2 ); vecInteger.push_back( 3 ); vecInteger.push_back( 2 ); vecInteger.push_back( 5 ); std::vector< int > vecOutput; std::remove_copy_if( vecInteger.begin(), vecInteger.end(), std::back_inserter( vecOutput ), std::not1( std::bind2nd( std::equal_to< int >(), 2 ) ) );우리가 원한 결과입니다.
조건자에 std::not 시리즈를 사용하기 위해서는 술어 함수, 즉 Logical 함수가 필요합니다.
술어함수가 되기 위해선 조건식 함수자가 std::unary_function, std::binary_function을 상속 받아야 합니다.
그 이유는 result_type이 필요하다고 합니다. 사실 bool을 리턴하긴 해야 하니까요.
따라서 std::copy_if를 쓰시려면 std::remove_copy_if와 std::not 조합으로 쓰시면 되구요.
혹시 std::remove_copy_if가 보이신다면 std::not1, std::not2 함수가 보이는지 살펴보세요.
좀더 명시적으로 사용하려면 std namespace 안에 copy_if를 정의하는 것도 방법이겠지만,
표준화 위원회에서는 std namespace안에 다른 함수를 정의하는 것을 추천하지 않는다고 합니다.
라이브러리 사용자 입장에서는 일단 이렇게 써야겠습니다.
혹시 이 글을 보시고 더 좋은 방법을 알고 계신분은 댓글로 알려주시면 감사드리겠습니다.
- 이 글의 트랙백 주소
- 이 글에는 트랙백을 보낼 수 없습니다
-
- ohyecloudy @ 2010/10/11 06:05
-

-
http://groups.google.co.kr/group/comp.lang.c++.moderated/msg/aad7ccfb47ce0978?pli=1
글에서 copy_if()에 대한 비야네 아저씨 답변을 볼 수 있습니다.
저도 관련 글을 썼는데, 링크를 남겨 놓을께요.
http://ohyecloudy.com/pnotes/archives/308
add
- 댓글 남기기







MMORPG에서_좁은_지역에_유저_N명이_모여_있을때_처리_방법.pdf

AbstractFactory.zip























