C++

· C++
만약 public을 통해 다중상속을 한다면 static_cast를 통해 쉽게 상위 클래스로 형변환이 가능하다.하지만 부모의 멤버를 감추기 위해 private으로 상속한다면 static_cast를 사용할 수 없다.struct A { unsigned int data;};struct B { unsigned short data;};class C : A, B {public: C() { A::data = 0xA; B::data = 0xB; C::data = 0xC; } unsigned char data;};다음과 같은 상황이라고 치자. 이때 클래스 C로 변수를 만들면 메모리 뷰 관점에서는 다음과 같을 것이다. (public 상속을 해도 같은 결과가 나온다)[A:4byte][B:2byte][C:1byte] 만약..
· C++
소개vcpkg는 microsoft에서 개발한 패키지 매니저로, 파이썬의 pip와 같이 커맨드라인을 통해 패키지를 설치할 수 있도록 하는 프로그램이다. 이 글에서는 내가 직접 Microsoft/vcpkg 레포지토리에 PR을 올려 머지된 경험을 바탕으로 작성되었다.더 자세한 내용은 여기를 참고해보자.순서vcpkg에 새로운 패키지를 업로드하는 과정은 다음과 같다.CMakeList 수정vcpkg 포크(fork) 후 리모트 변경port 작성 후 커밋 & push최종적 PR 보내기vcpkg에서 port란vcpkg에는 우리가 작성한 라이브러리 코드가 들어있지 않고, 저장소의 이름과 버전 SHA 해시를 가지고 있다.우리가 작성해야 하는 port는 각각의 라이브러리의 버전과 설치 방법에 대한 내용이 담겨있는 정보이다.사..
· C++
서론게임 서버 프로젝트에서 로직 스레드를 싱글로 변환했다. 로직스레드가 싱글로 돌아가기 때문에 I/O에서 블로킹이 일어나면 그만큼 처리의 레이턴시가 생기는 것이기 때문에 이를 개선하기 위해 데이터베이스 쿼리를 비동기로 실행하고, 완료 콜백을 호출할 시스템을 구현하기로 했다. 본격 비동기화 시키기따로 데이터베이스 쿼리를 처리할 스레드를 생성할까 했지만, 스레드와 스레드가 데이터를 주고받는것 자체가 지연이 생길 수 밖에 없어 좋지 않아 보였다. 그렇다고 각 쿼리마다 스레드를 파는 것은 너무 효율이 떨어지는 방법이다. 가장 단순한 방법으로 task를 생각했다. task는 promise, future, packaged_task, async 등을 사용해 개발하는 것이다.task의 구현 자체는 스레드의 wrappe..
· C++
C++ 라이브러리 시스템C++은 다른 언어들과 다르게 라이브러리가 소스파일이 아니라 라이브러리 바이너리와 헤더로 나뉘어져 있고,컴파일 과정에 헤더의 경로를 등록시키고, 라이브러리 바이너리를 링크 시켜주어야 한다.그로 인해 새로운 라이브러리를 사용할 때마다 따로 컴파일, include 경로, 라이브러리 링크 등을 설정해주어야 한다.내가 사용한 기존의 방법git에서 submodule로 라이브러리를 추가하고, 배치파일 스크립트를 통해 CMake로 각각을 빌드하고 특정 폴더에 라이브러리 바이너리를 복사했다. 그 후 비주얼 스튜디오 프로젝트 설정에서 라이브러리를 등록해 사용했다.하지만  배치파일 스크립트를 통해 커스텀으로 라이브러리를 컴파일 하기때문에 새로운 라이브러리를 추가할 때마다 빌드 스크립트의 작성과 프로..
· C++
개발 배경MMORPG 팀 프로젝트 기획 중 서버에서 혼자 구현하지 못할 만큼의 컨텐츠를 기획하게 되었다... 이 상황을 해결하기 위해 고민하던 중 포톤에서 사용하던 RPC방식이 떠올렸다.RPC는 네트워크에서 복제된 객체에 대해 원격으로 함수를 호출해 서버에서 따로 로직을 구현하지 않고 클라이언트에서  구현하므로 개발 속도가 빨라지기 때문이다. 구현 이론RPC를 구현하기 위해선 다음 정보를 직렬화해야 한다.메서드 식별용 아이디브로드캐스팅 타깃RPC 호출자 아이디메서드 인수 목록클라이언트에서 RPC를 호출하면 데이터를 직렬화시켜 서버에게 보내고, 서버는 타깃에게 이 직렬화 데이터를 브로드캐스팅 하게 된다. 그 후 클라이언트에서 RPC 데이터를 받게 된다면 메서드 식별 아이디와 메서드 인수 목록을 역직렬화 시..
나는 메모리 풀을 구현할 때 다음과 같이 구현했다.static T* Pop(){ T* ptr = nullptr; if (!m_pool.empty()) ptr = m_pool.pop(); else ptr = new T; return ptr;}하지만 Pop을 호출하는 순간 엄청난 new의 콜스택이 쌓여 스택 오버플로우가 발생했다. 아무리 생각해도 new가 new를 호출할 일이 뭐가 있지 싶었지만, 얼마 지나지 않아 이유를 찾았다.바로 내가 풀링을 구현한 방식 때문이였다. 클래스에서 매크로를 사용해 new를 오버로딩하게 만들어 new를 호출할 때 오브젝트 풀에서 Pop을 호출하게 하는 식으로 구현했다.ptr = new T;그래서 이 코드에서 또 new를 호출하고 Pop을 하게 만..
메모리 배치 컴퓨터는 한 번에 처리할 수 있는 비트 수를 워드(word)라고 부른다. 만약 컴퓨터가 64비트라면 워드의 크기는 8바이트고, 32비트라면 4바이트이다. 컴퓨터에서 데이터를 한 워드안에 읽어 효율적으로 읽기 위해서 데이터의 크기별로 메모리에 배치한다. 만약 단위가 1이라면 어디에든지 배치가 가능하고, 2라면 2의 배수의 메모리 주소에 배치가 된다. 만약 4바이트 정수형(int) 데이터 하나가 워드와 워드 사이에 존재한다면 2번 연산을 해야한다는 문제가 발생한다. 배치 단위 확인하기 비주얼 스튜디오에서 클래스 위에 마우스 커서를 대보면 맞춤(Alignment): 8바이트라고 정적 검사를 통해 보여준다. IDE에서 확인하는 방법 말고도 소스 코드를 통해 확인하는 방법이 있다. cout
서버를 개발하던 중 갑자기 kernalbase.dll에서 애러가 떴다. 필자는 분명 커널에서 애러가 났고, 커널이 관리하는 IOCP에서 비동기 Accept동작을 걸었으니 여기서 애러가 난 것이라 생각했다. 하지만 이것은 반은 맞았고 반은 틀린 생각이였다. 놀랍게도 애러는 바로 getchar에서 일어난 것이였다. 비동기 작업을 걸기 전 io처리 스레드(GQSC; GetQueuedCompletionStatus()가 있는 스레드)가 커널모드에서 활성화 되지 않은 상태에서 주 스레드가 terminated되었을 땐 문제가 발생하지 않았다. 문제가 발생하는 상황은 비동기 작업을 걸어 io처리 스레드가 활성화 되고, 아무 문자를 입력해 main스레드에서 getchar를 실행하게 되었다. 하지만 getchar는 thr..
index1207
'C++' 카테고리의 글 목록