공부/SFML

vector, iterator, list, LinkedList 자료구조, SFML Framework 준비, InputManager, 싱글턴 디자인 패턴, Resource Manager, map, 비주얼 스튜디오 자체 에러 문제 해결

월러비 2025. 6. 26. 19:29

짧은 설명

  • 배열 : 저장 및 순회해서 비교
  • 포인터는 nullptr이 기본값이다

vector

  • 값을 넣지 않아도 기본값은 ‘0’이다.
vector<int> v1;                    // 빈 벡터
vector<int> v2(5);                 // 크기 5, 모두 0으로 초기화
vector<int> v3(5, 10);             // 크기 5, 모두 10으로 초기화
vector<int> v4 = {1, 2, 3, 4, 5}; // 초기값 지정
  • []: 인덱스 연산자도 사용할 수 있다.
  • size()를 이용해서 순회도 가능하다.
  • stl에는 순회용 또는 포인터를 위해 존재하는 클래스가 있다.
    • iterator 클래스다.
    • begin(), end() : 이 둘이 iterator 객체다.
      • 처음과 끝의 요소를 반환하는 함수다.

vector 함수

  • vector.push_back(데이터형과 같은 값) : 배열의 맨 뒤에 인자로 들어온 값을 할당하는 함수다.
  • vector.size() : 배열의 사이즈를 반환하는 함수다.
  • vector.pop_back() : 배열의 맨 뒤에 값을 삭제하는 함수다.
  • vector.insert(삽입 위치, 요소) : 중간 삽입
    • ex) v1.insert(v1.begin(), 100);
    • v1.insert(v1.begin() + 2, 100); ⇒ 3번째 위치에 삽입
  • vector.erase(삭제 위치) : 중간 삭제
    • ex) v1.erase(v1.begin() + 2);
  • vector.erase(시작 위치, 끝 위치) : 범위 삭제
    • v1.erase(v1.begin(), v1.begin() + 2); ⇒ 끝 바로 전까지 삭제 / 즉, 1 ~ 3까지니까 1번과 2번만 삭제된다.

iterator

std::vector<int>::iterator

for (std::vector<int>::iterator it = v1.begin(); it != v1.end(); ++it)
{
		std::cout << *it << std::endl;
}

auto it = v1.begin();
std::cout << *(it + 3) << std::endl; //it의 4번째 요소값이 반환된다.
  • 데이터형은 T 인자를 공유한다.
  • 반복변수라고 생각하면 된다.
  • std::vector<int>::iterator를 auto로 대체할 수 있다.
  • 포인터 연산자로 참조해야한다.
  • begin은 std::vector<int>::iterator 데이터형을 반환한다.
  • ++it : ++ 연산자가 재구현 되어있는 것이다.
  • *it : * 연산자가 재구현 되어있는 것이다.
    • 출력 결과는 v1의 첫번째 요소가 반환되는 것이다.
    • 즉, 포인터처럼 주소를 가리켜 * 연산자로 값을 반환하는 용도로 사용한다.
    • ++it는 다음 주소의 요소를 가리키게 된다.
  • iterator는 vector에만 사용하는게 아니라 stl의 모든 클래스에도 사용된다.
    • east?에도 똑같이 begin()을 사용해서 순회가 가능해진다.
  • begin() : iterator 객체를 생성해서 반환한다.
    • 역할 : 첫번쨰 요소를 찾아 iterator 객체로 만들어 반환한다.
  • 주의점 : end()는 끝 요소를 리턴하는것이 아니다.
    • 끝이 아닌 그 다음에 해당하는 위치의 iterator가 리턴되는 것이다.
    • 끝 그 다음의 용도 : 빈 공간 그 이전까지 순회하라는 뜻이다.
    • 조건식 < 을 생각하면 된다.
    • push_back의 값이 들어올 위치가 이곳이다.
  • 중간값 삽입 및 삭제도 iterator를 사용한다.

list

  • LinkedList : iterator 관련 클래스다.
  • 산술 연산이 불가능하다. ⇒ 랜덤 액세스가 불가능하다.
    • 랜덤 액세스 : v1.begin() + 2 같이 주소에 +해서 다음 요소에 접근하는것이 안된다.
  • 대신, push_front() 함수가 있어서 앞 뒤에 자유롭게 넣을 수 있게된다.

list 함수

  • push_front(요소) : 배열의 앞에 삽입
  • list.erase(v1.begin(), v1.end() ) : 전체 지우기

LinkedList 자료 구조

  • 순차적 자료구조(컨테이너)다.
  • 값 + 다음 노드(위치)의 주소 가 저장되어있다.

배열과 차이점

  • 배열 : 찾을 위치를 알면 + 연산을 해서 해당 위치를 접근이 가능하다.
    • 특정 요소 삭제시 하나씩 땡겨야한다.
  • 링크드 리스트 : 처음부터 N 번째까지 접근해야 찾을 위치에 접근이 가능하다.
    • 특정 요소 삭제시 그 노드만 빼고 주소를 그 다음 주소로 연결한다. ⇒ 삽입 삭제가 배열보다 편하다.
  • 빈번하게 삽입 삭제가 일어난다 ⇒ 리스트가 유리 / 저장과 순회가 빈번하게 일어난다 ⇒ 배열이 유리

SFML Framework 준비

  • 불편했던 점
    1. 텍스쳐, 폰트, 사운드 등 반복적인 리소스 생성
      1. 리소스 로드 및 언로드
    2. 상호 작용 - 키보드 을 눌리는지 확인하고 재사용할 수 있게
      1. 입력처리 : 이벤트 루프
      2. 키보드 뿐만 아니라 마우스도
  • 인풋 매니저, 리소스 매니저(로드, 언로드) 초기버전(템플릿으로) 생성

방법

  1. static 멤버를 써서 싱글턴 패턴의 전역 변수처럼 쓴다.

InputManager

  • 키 눌림 및 해제 확인
    • 매 프레임 업데이트때 확인한다.
  • list 함수를 사용한다.
//키 입력 확인
static bool GetKeyDown(sf::Keyboard::Key key); //눌렸을떄
static bool GetKeyUp(sf::Keyboard::Key key); //땠을떄
static bool GetKey(sf::Keyboard::Key key); //키 입력 확인
  • 키가 있는지 확인하고, 확인 후 삭제를 해야한다.
//키 있는지 확인 함수(키 리스트, 검사할 키)
static bool Contains(const std::list<sf::Keyboard::Key>& list, sf::Keyboard::Key key);
//키 있는지 확인 후 삭제 함수(키 리스트, 검사할 키)
static void Remove(std::list<sf::Keyboard::Key>& list, sf::Keyboard::Key key);
  • 초기화 및 키 초기화를 해야한다.
static void Init(); //초기화 함수
static void Clear(); //이벤트 루프 전 키 초기화 함수
  • 매 프레임 업데이트와 입력 이벤트를 처리할 업데이트가 필요하다.
//sf::Event& : 크기가 크기에 참조로 원본 그대로 가져와야 최적화에 좋다.
static void UpdateEvent(const sf::Event& ev); //이벤트 루프 호출 함수
//dt : 델타 타임
static void Update(float dt); //매 wjscp 루프(업데이트)때 해야할 함수

싱글턴 디자인 패턴

  • 특정 클래스의 객체가 클래스 처음부터 끝까지 하나만 유지되게끔 사용하는 패턴이다.
  • 이 하나뿐인 객체를 어디서든 접근하는것이다.
  • 하나만 유지되게 생성해야한다.
  • 코드 어디서든 접근할 수 있게끔 해야한다.
public:
	//싱글턴 인스턴스 반환
	static T& Instance()
	{
		static T instance; //스테틱 지역 변수
		return instance;
	}
  • 리소스 매니저에 사용한다.
  • 생성자를 public으로 두면 안된다.
    • 싱글톤은 객체가 하나만 있어야하기 때문이다.
protected:
	Singleton() = default; //= default == {} 즉, 아무 값도 없는것과 같은것이다.
	virtual ~Singleton() = default; //virtual : 소멸자는 자식객체도 소멸자 호출이 되어야하기 때문이다.
  • 대입연산자 및 복사생성자도 기본이 자동으로 뜨기때문에 지워야한다.
    • 코드 외부에서 사용하게 하면 강제로 지우게 하기 위해서다.
    • 복사하거나 대입하면 두 번째 인스턴스가 생길 수 있어 싱글톤의 의미가 깨지기 때문이다.
Singleton(const Singleton&) = delete; //복사 생성자의 외부 구현을 차단한다. / delete : 삭제
Singleton& operator=(const Singleton&) = delete;

스테틱 지역 변수

  • 지역 변수 : 함수 호출됬을 때 생성 / 함수 끝나면 소멸
    • 지역 안에서만 접근 가능
  • 스테틱 지역 변수 : 지역 안에서만 접근 가능
    • 차이 : 프로그램 시작했을때 메모리에 올라가고 프로그램 종료시 삭제
    • 함수가 끝나도 메모리에 남아있어서 읽고 쓸 수 있다.
    • 함수에 최초로 접근할 때 메모리에 올라간다.
    • 왜 함수에 선언하는가? : 멀티 쓰레드는 여러개의 프로그램을 사용하기때문에 메모리에 다른 쓰레드가 접근할때 그것을 막하야한다.
      • static은 멀티쓰레드의 접근을 조절하는 기능이 있다.

리소스 매니저

  • friend 하는 이유
    • ResourceMgr의 생성자가 외부 코드에서 사용하지 못하게 막혀있다.
      • new ResourceMgr<>()를 외부에서 사용하는것을 막는다.
    • Singleton 클래스는 내부적으로 new ResourceMgr<T>() 생성 작업을 해야한다.
      • 정적 인스턴스를 만들기 위해 new T() 또는 T()를 호출해야한다.
      • Singleton<ResourceMgr<T>> 클래스가 ResourceMgr의 생성자에 접근할 수 있어야 인스턴스를 만들 수 있다.
    • 즉, Singleton 클래스에서 ResourceMgr의 멤버에 생성자를 만들기 위해 friend를 선언해주는 것이다.
    • ex) T == Texture → static ResourceMgrsf::Texture instance; 호출
      • 생성자가 protected니까 sington클래스는 friend가 아니면 접근이 불가능하다.
      • friend 선언 필요
  • 템플릿 클래스 이기에 전역 설정도 템플릿으로 생성해야한다.
friend Singleton<ResourceMgr<T>>;

};

template<typename T>
T ResourceMgr<T>::Empty;
  • 리소스를 담을 컨테이너가 필요하다.
//std::string : 경로를 키로 받을것이다
std::unordered_map<std::string, T*> resources; //리소스 저장 맵
  • 로드, 언로드, get 함수가 필요하다.
//id: 파일 경로를 받는다.
bool Load(const std::string& id); //리소스 로드 (동적 할당) / bool : 로딩이 실패할 수 있기 때문이다.
bool Unload(const std::string& id); //리소스 언로드 (delete 할 예정)
T& Get(const std::string& id); //파일 경로를 받아서 그것을 키로 리소스 반환

map

  • map<key, value> : 균형 이진 탐색 트리 자료구조
    • 자동 정렬
  • unordered_map<key, value> : 해시 테이블 자료구조
    • 정렬이 안된다.
  • 둘 다 연관 컨테이너라고 분류한다.
    • 템플릿 인자 2개를 받는다.
    • 실제 값 : value
    • key : 값을 찾을 값이다.
      • 키를 이용해서 탐색하고 키를 이용해서 삭제한다.
  • 연관 컨테이너 : 탐색에 최적화된 자료구조다.
    • find는 효율적이지 않는다.
      • 처음부터 순회해서 찾아야하기 때문이다.
    • 탐색을 자주해야하고, 자료의 양이 많을때 사용한다.
    • 맵 변수명→first를 쓰면 key가 반환, 맵 변수명→second를 쓰면 value가 반환
  • 사용처
    • 정렬 필요 : 맵
    • 정렬 필요 없음 : 언오더드 맵
    • 사용 방법은 동일
      • 값 넣기 - 값 찾기 - 값 사용 순서다.

균형 이진 탐색 트리

  • 노드의 삽입과 삭제가 일어날 때 균형을 유지하도록 하는 트리다.

해시 테이블

  • 키를 사용하여 값을 저장하는 배열이다.

비주얼 스튜디오 자체 에러 문제 해결

  • .vs 폴더를 지움으로서 해결되는 문제들이 있다.
  1. 빌드 실패
  2. 프로젝트 설정이 이상해지거나, 빌드 구성이 이상한 경우
  3. 인텔리 센스 작동 안할때
  4. 비주얼 스튜디오가 비정상적으로 느려졌을 때
  5. 프로젝트가 실행은 되는데 이상한 경로에서 실행될 떄