[0618구경원]초보 게임프로그래머를 위한 c++
TRANSCRIPT
초보 게임프로그래머를 위한 C++
돼지고기 ( 구경원 )데브루키 6.18
개요
참조
참조
- 개체를 의미하는 하나의 다른 이름이다 .- 참조에 수행되는 작업은 원본 개체에 직접
영향을 준다 .
int A = 10;int& B = A; //B 는 A 의 참조다B = 300; //A 와 B 는 모두 300 이다 .
참조와 포인터- 포인터를 통한 접근은 -> 를 이용한다 .
참조를 통한 접근은 . 을 이용한다 .- 포인터는 만들고 나중에 초기화 할 수 있다 .
참조는 선언된 직후 반드시 초기화 해야한다 .- 포인터는 원하는 시점에 다른 개체를 가리키도록 할
수 있다 .참조는 처음 한번만 초기화 될 수 있다 .
- 포인터는 NULL 이 될 수 있다 .참조는 NUU 이 될 수 없다 .
참조 이용의 이점
- 포인터 보다 보기가 편하다 .int A = *(Entity->GetCount());int A = Entity.GetCount();
- NULL 을 가르키는 일이 없다 .참조는 선언과 동시에 초기화가 되여지기 때문에 포인터보다 잘못된 값을 가져올 확률이 낮다 .
참조 이용의 시기
- 함수 내에서 수정되지 않는 개체const 참조를 이용한 전달
- 함수 내에서 수정되어야 하는 개체포인터를 이용한 전달
초기화리스트
대입과 초기화
class A{
int AA;string STR;A();~A();
};
A::A(const string& _STR)
{AA = 0;STR = _STR;
}
초기화 된것이 아니라 대입 되어짐 .복사 대입 연사자 호출 .
대입과 초기화
class A{
int AA;string STR;A();~A();
};
A::A(const string& _STR)
: AA(0), STR(_STR)
{
}
초기화 리스트를 사용한 초기화 .복사 생성자 호출 .
사용 시기
- 상수 맴버 변수 const 상수변수는 선언과 동시에 초기화가 이루어 져야 한다 .
- 래퍼런스 맴버 변수레퍼런스는 선언과 동시에 가르키는 대상이 있어야 한다 .
- 포함된 개체포함된 개체의 생성자를 호출과 동시에 초기화 시켜주어야 할때 .
인라인
인라인 함수
- 인라인 함수변수에 직접 접근하는 것과 같은 효과를 제공 한다 .함수 호출을 제거하고 함수 코드를 추가하는 일은 컴파일러가 수행 .함수 호출과 관련된 성능 저하 문제가 완벽히 해결된다 .
주의점
- 주의사항인라인 될 함수는 헤더파일 내에 정의되어야 한다 .인라인 함수로 정의했다고 해서 100% 인라인이 된다는 보장이 없다 . ( 컴파일러가 결정 )
- 많은 인라인 함수 사용 .컴파일 시간의 증가 .소스파일의 크기가 증가 .프로그램 수행 속도의 저하 .
사용시기
- 사용은 언제 ?초기 개발 단계에서는 인라인 함수의 사용을 피하자 .어느 정도의 개발이 진척이 있으면 자주 호출되는 몇줄 안되는 함수에 대해서 인라인화 시킨다 .
TIP
무분별한 인라인 함수의 사용은 오히려 독 .컴파일러가 계속해서 인라인 적용을 거부하는 경우도 있다 . 그러므로 필요에 따라서 인라인 함수와 비슷한 매크로 함수를 사용하자 .
Define 토큰
#define 토큰
C/C++ 에선 #define 의 사용의 빈도를 자
제하도록 권고하고 있지만 , 잘 사용할 경우 많은 코드상의 이득을 볼 수 있다 .
#define 토큰종류
- ‘##’ 분리되어 있는 2 개의 토큰을 하나로 합쳐준다 .
- ‘#’매크로 인자를 문자열로 만들어 준다 .
##
#define AA(n) printf(“Game= %d”, Game##n)
int Game9 = 1004;AA(9)
Game = 1004;
#
#define Game(x) printf(#x “\n”)
Game(WorldOfWarcraft\n);
Printf(“WorldOfWarcraft\n\n”);
캐시메모리
- CPU 속도하루가 다르게 발전하고 있다 .
- 메모리 속도CPU 의 속도발전에 비해 상대적으로 발전이 느리다 .
이러한 격차의 조율문제는 개발자의 몫 !
- CPU 가 메모리의 느린 속도에 영향을 받지 않고 항상 최대의 성응으로 작동할 수 있을까 ?
메모리 캐시 활용
캐시메모리- 메모리 캐시
자주 이용되는 데이터와 코드를 임시로 저장하는데 이용되는 작지만 매우 빠른 메모리 이다 .
모든 데이터를 메모리 캐시에 보관 할 수 없다 .
- 좋은 상황CPU 가 필요로 하는 데이터가 캐시내에 보관되어 있는 상태 .
- 나쁜 상황캐시내에 데이터가 없어서 캐시미스 발생하며 메인 메모리가 준비될 때 까지 실행을 멈추고 기다리는 상태 .
캐시라인
- 가장 작은 단위독립적으로 들어오고 나갈 수 있는 가장 작은 메모리 단위 .대부분의 PC 에서 32 바이트 크기이다 . ( 최대 128 바이트 )
데이터의 크기를 32 바이트의 배수로 만들어 사용하면 효율적 .
맴버 변수의 위치
- 변수의 위치자주 이용되는 클래스 맴버 변수의 선언위치를 위쪽으로 옮기는 것만으로도 성능상의 이익을 얻을 수 있다 .
가상함수 vatable 를 가진다 .Vatable 는 객체의 시작부분에 위치하는 하나의 포인터이다 .즉 개체의 처음 32 바이트를 캐시에 올리는 효과를 가진다 .
TIP
메모리 내의 맴버 변수 순서 ?클래스 선언에서 정의된 순서와 일치 .
플러그인
플러그인의 필요성
도구
확장
확장
확장
확장
확장
확장
확장
확장의 연속
플러그인의 로딩
- 런타임시 로딩 프로그램의 일부가 되어서는 안 된다 .- Win32
가장 쉬운 Win32 함수를 이용한 DLL 로딩 .
사용 방법
- extern “C”컴파일러로 하여금 함수의 이름을 일반적인 C++ 방식으로 만들지 말고 C 함수와 같이 꾸미지 않은 상태로 유지하도록 하는 기능이 있다 .
- _declspec(dllexport)실행파일의 익스포트테이블에 함수를 넣어준다 .
사용 방법
- 플러그인 로딩HMODULE hDLL= ::LoadLibrary(“ 파일이름” );
- 함수 사용GetProcAddress(hDLL, “ 함수이름” );
- 플러그인 삭제FreeLibrary(“핸들명” );
단점
- 플러그인 간의 의존성에 문제점이 있다 .- 버전에 따른 플러그인 사이의 충돌이
발생할 수도 있다 .
STL
Find
시퀀스 내의 모든 항목 사이를 반복하면서 원하는 항목을 찾는 알고리즘 .Find(Name.begin(), Name.end(), WantName)
TIP
시퀀스 내의 요소들이 정렬되어 있지 않거나요소들 사이의 규칙성이 없는 상황에서만 알고리즘을 사용하는 것이 좋다 .
For_each
시퀀스 내의 각 요소에 대하여 특정한 함수를 실행하는 알고리즘 .for(itr = Entity.begin(); it != Entity.end(); ++itr)
(*itr).Update();
For_each(Entity.begin(), Entity.end(), Update);
For_each(Entity.begin(), Entity.end(), mem_fun_ref(::Update));
- For많은 사람들이 쉽게 이해 할 수 있는 구조를 가지고 있다 .
- For_each코드가 간결해지고 오류가 생길 여지가 적다 .다른 반복문에 비해서 반복루프시 속도가 빠르다 .
TIP
우선 순회를 시작하면 멈출 수가 없다 .그러므로 컨테이너 전체를 순회해야 하는 상황에서만 사용하자 .
Count
특정한 조건에 맞는 요소만을 세는 기능이 있는 알고리즘 . int nCount = count(
Entity.begin(), Entity.end(), 0);
int nCount = count_if(Entity.begin(), Entity.end(), EntityCheck());
TIP
편리한 기능을 제공하는 알고리즘 이기는 이지만 많은 요소에 대한 검사는 성능상의 문제를 가져올 수도 있다 .
Include가드
#include
전처리기에 의해 처리된다 .//Game.h#define MAX_PLAYER 10//Game.cpp#include “Game.h”stPlayer player[MAX_PLAYER ];
#define MAX_PLAYER 10stPlayer player[MAX_PLAYER ];
//GameState.h#include “Game.h”//Game.cpp#include “Game.h”#include “GameState.h”Player player[MAX_PLAYER];
쉽게 범할 수 있는 오류 .
#include 가드
동일한 컴파일 단위에 같은 파일이 두 번 이상 포함되는 것을 막아준다 .//Game.h#ifndef GAME_H_#define GAME_H_// 소스부분#endif
#include 가드
동일한 파일을 두 번 이상 포함되는 것을 막아주면서 파일을 두 번 이상 여는것도 막아준다 .
- #pragma once컴파일 속도가 앞의 가드보다 빠르다 .
C++ 표준에 포함되여 있지 않다 .지원해주지 않는 컴파일러도 있다 .
스마트포인터
스마트포인터
C++ 전문가들이 만든 차세대 메모리 관리자 .
boost 라이브러리에 포함되여 있다 .
std::auto_ptr //c++표준
boost::shared_ptr //앞으로 표준
메모리누수
Void main(){
Game* pp = new Game;// 수많은 예외발생//예> return; 존재 .delete pp;
}
프로젝트가 커질수록 수많은 예상외의 상황이 발생하고 , 그로 인해 메모리 누수가 발생할 수 밖에 없다 .
auto_ptr
#include <memory> 헤더안에 포함되여 있는 스마트 포인터이다 .
std::auto_ptr<Game> p(new Game);
자기 객체가 사라질때 소멸자에서 자동으로 delete 를 적용
시켜준다 .하지만 생성된 객체의 소유권은 오직 하나만 존재 한다 .
shared_ptr
참조 카운팅 방식의 스마트포인터로 C++ 의 새로운 표준인 tr1 에 포함되여있다 .
std::tr1::shared_ptr<Game> p(new Game); std::tr1::shared_ptr<Game> p2(p);
자원의 참조 개수를 체크한다 .소유권이 여러 개 존재할 수 있다 .
컴파일 속도
멀티코어 사용
VisualStudio 2005, 2008 에서 컴파일과정에는 멀티코어 CPU 를 지원하지 않는다 .
프로젝트 속성 -> C/C++ -> 명령줄 ->추가옵션 -> /MP 입력 .
멀티코어 CPU 를 지원한다 .
컴파일된 헤더 사용
전반적으로 사용되어지며 , 소스수정이 크게 없는 헤더파일을 미리 컴파일 해두고 , 다음에 빌드때마다 다시 컴파일 하지 않고 사용 하는 방법 .프로젝트 설정 .프로젝트 속성 -> C/C++ -> 미리컴파일된 헤더 ->
미리컴파일 된 헤더 사용
CPP설정CPP 의 속성창에서 위와같이 설정 .
컴파일 속도 증가 .
증분링크 사용
Obj 파일을 합치는 과정에서 메모리배치 , 함수 순서 , 코드 , 데이터영역 등을 계산하는 시간이 포함되여 있다 . 그래서 매번 수정된 것만을 재계산 하게 하는 방법이다 .
프로젝트 속성 -> 링커 -> 일반 -> 증분링크사용
링크속도 증가 .
끝