[C++] std::move 와 std::forward
[C++] std::move 와 std::forward
2022.04.09언제 std::move를 사용해야 하는지, 언제 std::forward를 사용해야 하는지 알아보는 시간을 가져보도록 하겠습니다. 1. std::move std::move의 경우 형변환 작업을 수행합니다. 받은 param에 대해 R-value reference를 반환합니다.예를 들면 이런 식 입니다. #include void Function(int&& Arg) { std::cout
[C++] STL Custom Allocator 사용
[C++] STL Custom Allocator 사용
2022.04.08Custom Allocator를 사용해서 STL Container들이 사용할 버퍼를 공급할 수 있습니다. STL Cotainer는 Element가 들어갈 Container Buffer의 할당시 템플릿으로 구현된 Allocator 클래스를 사용합니다. STL에서의 할당 동작시의 힙 파편화가 우려되는 상황이라면, 커스텀된 Allocator 클래스를 우리가 직접 구현하고, 미리 구현해둔 메모리풀로 이어지게 해서 통제할 수 있습니다. 우선 STL Cotainer의 할당시 동작의 이해를 위해서 아주 간단한 allocator 클래스를 구현하겠습니다. 할당시 동작할 내부 구현을 바꿔서 프로젝트 상황에 맞게 사용하시면 되겠습니다. 물론 말씀드렸듯이 STL Cotainer는 템플릿을 통한 호출을 하기 때문에 함수의 시그..
캐시메모리와 Cache Friendly Code
캐시메모리와 Cache Friendly Code
2022.04.031. 캐시메모리는 무엇인가? 캐시메모리의 핵심 개념은 locality이다. 레지스터에 가까운 지역에 전진기지를 만들어 그 안에 자주 사용하고(temporal locality), 인접한(spartial locality) 데이터를 보관하기 위해 고안되었다. 잘 알려져 있듯이 메인메모리보다 크기가 작다. 이 작은 꾸러미를 최대한 활용하기 위한 하드웨어 알고리즘은 지금도 개발되고 있다. 허나 이것은 어디까지나 한계가 있는 이야기이다. 전 지구상에서 지금도 개발되고 있는 모든 어플리케이션의 분기를 예측하는 것은 불가능에 가깝기 때문이다. 따라서 개발자 또한 어느정도는 캐시메모리를 이해하고 코드를 짜는 것이 최적화에 매우 유리하다고 할 수 있다. 찾는 데이터가 캐시메모리에 보관되어 있다면, 캐시 히트 라고 한다. ..
멀티스레드 환경에서의 캐시 라인에 대한 주의사항
멀티스레드 환경에서의 캐시 라인에 대한 주의사항
2022.04.02OS는 프로세서의 정보를 얻을 수 있는 API를 제공한다. 윈도우즈의 경우 다음과 같이 작성해보자. #include #include int main() { SYSTEM_LOGICAL_PROCESSOR_INFORMATION* pInfo = nullptr; unsigned long length = 0; GetLogicalProcessorInformation(nullptr, &length); pInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION*)malloc(length); GetLogicalProcessorInformation(pInfo, &length); //OS가 알려주는 length는 SYSTEM_LOGICAL_PROCESSOR_INFORMATION의 크기 * N이다. //..
[C++] C++ 11 mutable
[C++] C++ 11 mutable
2022.03.28C++11 에 mutable keyword가 추가 되었다. 아래의 간단한 코드를 보도록 하자. 너무 간단하다. #include class Entity { private: int A = 10; mutable int B = 20; int C = 30; public: Entity() {} virtual ~Entity() {} void Function() const { //A = 20; //컴파일 에러 함수 선언에 const가 붙었다. B = 30; //Okay. //B에는 mutable 키워드가 붙었음으로 const가 붙은 함수에서도 B값에 대한 수정이 허용된다. } }; mutable은 멤버 변수 혹은 람다에서 사용이 가능하다. int main() { mutable int A = 10; //무의미하다. //..
[C++] C++11 override, final
[C++] C++11 override, final
2022.03.28C++11 에 override 와 final 키워드가 추가되었다. 아래의 코드를 보도록 하자. 1. override #include class EntityBase { public: virtual void Print() { std::cout
[C++] new[] , delete[] 오버로딩시 주의 사항.
[C++] new[] , delete[] 오버로딩시 주의 사항.
2022.03.281. 연산자 vs CRT 함수 동적할당이라는 단어에 대해서 잘 생각해보아야 한다.우리가 힙이라고 부르는 것은 풀어쓴다면 다음과 같다. "스택 프레임과 별개로 프로그래머가 내킬때 해제할 물리메모리" 동적 할당은 OS자원에 대한 요청이다. OS에게 "스택 프레임과 별개로 프로그래머가 내킬때 해제할 물리메모리" 에 대한 요청을 한다. OS에게 물리메모리에 사용에 대한 허락을 받으면,우리는 힙에 할당되었다고 이야기 하는 것이다. 핵심은 new와 delete는 연산자이고 malloc 과 free는 CRT 함수이다. new와 delete가 연산자라는 말은, 어디까지나 C++ 컴파일러가 인식하는 키워드 라는 것이다. 컴파일러는 new와 delete를 발견하면 일련의 기계어 동작으로 해석해낸다. 그리고 그 일련의 기계..
[C++] const lvalue reference, rvalue reference
[C++] const lvalue reference, rvalue reference
2022.03.23C++11에 std::move 그리고 std::forward 가 추가 되었다. 우선 lvalue와 rvalue 의 개념을 이해해야 제대로 사용할 수 있을 것 같아 정리하기로 한다. 1. lvalue lvalue는 이름이 있는 값이다. 그러니까, C++ 코드에서 변수명을 정한 값이 바로 lvalue이다. 글로 표현할수록 오개념이 생길 수 있다. 아래의 아주 간단한 코드를 보도록 하자. int IamInt = 10; //IamInt는 lvalue이다. //이름에서 알 수 있듯 대입시에 좌측에 위치한다. //IamInt 라는 이름을 가졌기 때문에, 이 곳으로의 값의 복사는 //위 처럼 간단하게 가능하다. 아주 쉽다. 우선은 우리가 아는 variable 의 개념이 lvalue라고 이해하자. 하나의 예시를 더 보..
[C++] C++11 constexpr
[C++] C++11 constexpr
2022.03.20상수는 어떤 특징을 가지는가? 컴파일타임에 약속되고, 절대 변하지 않는다는 보장이 있어야 한다. 이러한 점을 컴파일러에게 알려주는 키워드가 바로 constexpr이다. 기존 const가 있는데 왜 constexpr이 따로 생겼나요? 아래의 예시를 보도록하자. 1. const #include int main() { //const std::size_t Size = 10; //int Array[Size]; //가능. //초기화 이후 바뀌지 않는다. //그렇다면 만약 ? const std::size_t Size = 10; size_t* Casted = const_cast(&Size); *Casted = 50; int Array[Size]; std::cout
[C++] 스마트 포인터 unique_ptr, shared_ptr, weak_ptr
[C++] 스마트 포인터 unique_ptr, shared_ptr, weak_ptr
2022.03.19C+11에 템플릿으로 구현된 세가지의 스마트포인터 unique_ptr, shared_ptr, weak_ptr가 추가되었다. 아마도 가장 많이 사용하고 있지 않은가 싶다. 특히나 C++로 게임을 만드려고 한다면 객체의 생명주기 관리를 위해 잘 알아두는 것이 좋겠다. 1. unique_ptr 대입 연산자를 막아버렸다. 의도는 명확하다. 다른곳에서 참조하지 말라는 의미다. 물론 get을 호출하면 raw pointer를 얻을 수 있다. 그럼 사실상 무의미 해진다. #include #include class MyInstance { public: void operator delete(void* pAddress) { std::cout
[C++] Type Casting 연산자 정리 static, dynamic,reinterpret, const
[C++] Type Casting 연산자 정리 static, dynamic,reinterpret, const
2022.03.17모든 데이터는 바이너리 데이터로 이루어진다. 포인터에 대한 형변환은 언어에게 그냥 해당 주소안에 있는 데이터를 이 형태로 취급해라 라는 정도이다. 그래서 어떤 어드레스에 대해 역참조를 하면 포인터의 형태가 int* 이면 4byte를 읽어들이고, long long 형이면 8byte를 읽어 들이는 것 뿐이다. 다만 이런 캐스트 연산자를 사용하는 이유는 언어 차원에서 뭔가 의도한건 아닌거 같은데? 정도를 잡아내게끔 할때이다. 1. static_cast int* From = new int; void* To = static_cast(From); //No. int* From = new int; void* To = static_cast(From); //No. long long* From = new long long;..
[MSSQL] Clustered Index, Non-Clustered Index
[MSSQL] Clustered Index, Non-Clustered Index
2022.03.16데이터베이스는 머신의 하드디스크 혹은 SSD에 위치한다. 디스크의 헤드가 도는 속도는 느리다. 양보해서 SSD라 할지라도, 테이블의 레코드의 양이 많아지면 많아질수록 원하는 특정 레코드에 대한 쿼리는 점차 부담스러운 일이 된다. 이때에 인덱스를 적절하게 활용하면 성능을 개선시킬 수 있다. SQL Server에서의 인덱스 방식은 주로 두가지 방식에 대해서 이야기한다. Clustered Index와 Non Clustered Index. 두가지 인덱싱 방식은 매우 유사하면서도, 차이를 보인다. Clustered Index 이름에서 알 수 있듯 테이블과 인덱스가 결합되며, 인접한 인덱스의 레코드가 결합되는 방식이다. (특정 키값을 컬럼에 가진 레코드를 찾을때 결합된 인덱스가 내부에 있고 이를 이용한다고 생각하자..