일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 람다
- map
- 언리얼엔진구조체
- 정렬알고리즘
- 데이터애셋
- 스마트포인터
- UE4 커스텀로그
- 프로그래머스
- C++최적화
- 람다사용정렬
- 선택정렬
- 자료구조
- unorder_map
- dataasset
- 델리게이트
- 정렬
- C++
- UELOG
- UML관련
- 약참조
- 애셋로드
- 알고리즘
- 크리티컬섹션
- moreeffectiveC++
- enumasByue
- 강참조
- stl
- UE_LOG
- 언리얼가비지컬렉터
- BFS
- Today
- Total
목록C & CPP (88)
기억을 위한 기록들
클래스 이전에 구조체가 있었다. 구조체 멤버의 기본 접근 지정자는 public이고 클래스의 접근 지정자는 private으로 되어있다. 왜 그런 걸까? 하고 보면 원래 C언어에서 먼저 구조체가 만들어졌고, 접근 지정자의 개념이 없었다. 그러다 C++ 이 추가되고 캡슐화 및 정보은닉의 개념을 구현하기 위해 도입된 것이다. 구조체는 처음부터 외부에서 자유롭게 접근되었기에 기본 접근 지정자는 public인것이고 클래스는 private인 것이다. 클래스의 메모리 구조 클래스를 이해한다는 것은 클래스의 메모리 구조를 이해하고 컴파일러가 어떻게 그 구조를 이용하는지를 아는 것이 거의 전부라고 할 수 있다. 어떤 클래스로 예를 보자 class CTest { public: int mInt; char mChar; stat..
함수에서의 배열 전달 #include #include using namespace std; int DoSomething(int arr[]) { arr[0] = 1; arr[1] = 2; arr[2] = 3; return sizeof(arr); } int main() { int myArr[3] = { 0 }; int s = DoSomething(myArr); for (auto value : myArr) { cout
- 메모리의 주소를 가리키는 객체를 포인터라고 부른다. - 메모리 블록은 주소, 크기, 상태의 정보를 가지고 있다. - 메모리 블록을 쉽게 관리할 수 있도록 포인터에는 주소뿐 아니라 타입 정보까지 들어가게 되었다. 타입 정보를 통해 메모리 주소로부터 타입 크기만큼 블록에 값을 읽거나 쓸 수 있게 된 것이다. 포인터 타입 - int 타입 객체를 기리 키기 위해 int* 타입 포인터를 사용하는 것이 쉽게 편해서 장점이 많다는 것이지, 반드시 int* 을 사용해야만 하는 것은 아니다. 필요에 따라 다른 타입이 int타입을 가리킬 수도 있다. 같은 경우 int a = 0; int* ptr = &a; *ptr = 3; //역참조 값 변경 std::cout
가상메모리 핵심은 각각의 프로세스에게 메모리 공간이 독립적으로 부여된다는 것. 개별 프로세스는 부여받은 메모리 영역은 해당 프로세스만이 접근할 수 있도록 보호된다. 독립적으로 부여되어 타 프로세스가 해당 메모리 영역을 침범할 수 없고, 안정성을 크게 향상 가상메모리의 크기 x86는 32비트 시스템이다. 주소를 가리킬 수 있는 레지스터의 크기가 32비트라는 의미. 이론적으로 2의 32승인 대략 42억 개의 주소가 나오고 각각의 주소가 1바이트씩 가리킬 수 있으므로 각각의 프로세스는 4GB의 메모리를 부여받고, 윈도우의 경우 부여된 4GB의 절반은 운영체제가 사용. 나머지 2GB만 사용가능하게 된다. x64는 64비트 시스템이며 레지스터의 크기가 64비트이므로 이론적으로는 2의 64승 개의 주소를 사용할수 ..
빌드는 크게 3단계로 나뉜다. 1. 전처리 2. 링크 3. 컴파일 정적 라이브러리를 생성하는 경우는 링크 과정이 필요하지 않다. 최종 목적의 바이너리를 만들어내기 위해 거치는 과정(전처리, 컴파일, 링크 등) 모두를 '빌드'라고 한다. 컴파일 컴파일의 대상은 소스 파일 즉, cpp파일이다. 헤더 파일(. h)은 컴파일의 대상이 아니다. 헤더파일은 특정 cpp파일 안의 #include 구문에 의해 포함될이다. 특정 cpp 파일이 컴파일되면서 #include에 의해 포함된 헤더 파일의 내용이 같이 컴파일되는 것뿐이다. 즉 헤더 파일은 단독으로 컴파일되지 않는다. 소스파일이 컴파일되면 목적(object)파일이 생성된다. 소스 파일과 목적 파일은 일대일 대응관계라고 할 수 있다. 소스파일이 사람이 이해하는 파일..
정의 해당 객체를 위해 메모리 영역을 확보하는 것 클래스 정의 : class CTest { public: int a; int b; }; 선언 어떤 객체가 존재하고 있음을 알리는 역할 class CTest; //선언 CTest myTest;//사용 정의는 선언을 포함한다. 어떤 객체를 정의하는 순간 해당 객체는 알려지므로 선언을 따로 해줄 필요가 없다. 그렇다고 선언이 불필요한 것은 아니다.(전방 선언 등) - 같은 이름의 전역 변수는 실행 공간에 오직 단 한 번만 정의될 수 있다. //A.cpp int g_ValA; //Ok int g_ValCommon; //Link Error //B.cpp int g_ValB; //Ok int g_ValCommon; //Link Error - 같은 이름의 정적(stat..
두 객체의 값을 맞바꿔주는 각자의 값을 상대방에 주는 동작이다. 표준 라이브러리의 swap도 아래와 같이 생겼다. namespace std { template void swap(T& a, T& b) { T temp(a); a = b; b = temp; } } 코드를 보면 알겠찌만 복사만 제대로 지원하는 타입이기만 하면 어떤 타입의 객체든 swap이 가능하다. 하지만, 호출 한번에 복사가 3번씩 일어난다 a에서 temp로 b에서 a로 temp에서 b로. 복사를 하게 되면 손해를 보는 타입들 중 으뜸은 아마도 다른 타입의 실제 데이터를 가리키는 포인터가 주성분인 타입일 것이다. 이런 개념을 많이 쓰고 있는 기법이 바로 pimpl 관용구(pointer to implementation)이다. pimpl 설계를 ..
1. 원래의 vector 일반 vector는 보통 이렇게 사용한다. std::vector arr; arr.push_back(1); arr.push_back(2); arr.push_back(3); 순서대로 들어가게 된다. 2. 2차원 vector 하지만 2차원 배열은 어떻게 써야할까? 우선 자료형 안에 또하나의 vector를 선언 해준다. std::vector arr2; 그리고 똑같이 넣어보려 했으나... std::vector arr2; arr2.push_back(1);//에러! 컴파일 에러가 발생한다. 해결로는 std::vector arr2; std::vector arr; 별도의 int 자료형만 담는 vector를 만들어주고, std::vector arr2; std::vector arr; arr.push..
타입 변환이 모든 매개변수에 대해 적용되어야 한다면, 비멤버 함수를 선언하자. 예를 들어 유리수를 나타내는 클래스를 만들고 있다면, 정수에서 유리수로의 암시적 변환을 허용을 판단해도 크게 어이없거나 하진 않을 것이다. C++에서 제공하는 int -> double 변환과 별반 다르지 않다. 유리수를 나타내는 클래스를 하나 보자. class Rational { public: Rational(int num = 0, int denom = 1); //num=분자 / denom=분모 const Rational operator*(const Rational& rhs) const; int GetNum() const; int GetDenom() const; private: //... }; 유리수를 나타내는 클래스이니, o..
어떤 캐릭터 클래스를 만들다가 캐릭터가 죽어서 다시 처음부터 진행되기 위해 상태를 초기화해주는 함수들이 있다고 가정합시다. class Character { public: //.. void SetMaxHP(); //최대체력 만들어주기 void ClearStat(); //능력치 초기화 void ClearInventory(); //인벤토리 비우기..등 //.. }; 이렇게 3개면 기획상의 추가로 점점 많이지게 되면, 한 번에 호출하고 싶게 된다. class Character { public: //.. void SetMaxHP(); void ClearStat(); void ClearInventory(); //.. void ClearEverything() //한번에 호출해주는 함수 추가 { SetMaxHP(); ..
그렇게 생각해야하는 이유 2가지 첫 번째 이유 문법적 일관성이다. 데이터 멤버가 public이 아니라면, 사용자 쪽에서 어떤 객체를 접근할 수 있는 유일한 방법은 멤버 함수일 것이다. 그러면 괄호를 붙어야 하는지 말아야 하는지 고민할 필요가 없어진다.(무조건 괄호) Vector a; a.DoSomething(); //괄호를 붙어야할지 말아야할지 고민할 필요가 없을 것이다. 그리고 멤버변수가 public이면 읽기뿐만 아니라 쓰기 권한을 통제하기 애매해진다. getter/setter 등으로 확실히 하는 게 좋다. 두 번째 이유 캡슐화이다. 함수를 통해서만 데이터 멤버에 접근할 수 있도록 구현해두면, 데이터 멤버를 계산식으로 대체가 가능할 수도 있다. 상황 예) 예를 들면 여러 캐릭터를 조종 할 수 있는 게임..