일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 데이터애셋
- 프로그래머스
- unorder_map
- 강참조
- 언리얼엔진구조체
- moreeffectiveC++
- 알고리즘
- 크리티컬섹션
- 정렬알고리즘
- 람다
- enumasByue
- 람다사용정렬
- 애셋로드
- BFS
- UE_LOG
- 언리얼가비지컬렉터
- 스마트포인터
- UML관련
- 약참조
- C++최적화
- C++
- UE4 커스텀로그
- map
- dataasset
- stl
- 델리게이트
- 정렬
- 자료구조
- 선택정렬
- UELOG
- Today
- Total
목록C & CPP (88)
기억을 위한 기록들
c++를 그래도 나름 공부했다고 생각하고, 이펙티브 c++를 보며 공부하다가 그 사이에서도 이전에 간과하거나, 애매하게 아는 부분들을 다시 공부해보고 싶어서 추천받아 산 책이다. 이책하고 이펙티브C++책하고 같이 볼것같다. 참고한 책 : www.yes24.com/Product/Goods/16362643?OzSrank=1 Fundamental C++ 프로그래밍 원리 이 책은 C++ 프로그래밍의 문법과 사용 방법보다는 C++ 그 자체에 초점을 두었다. 즉, C++ 프로그래밍이 어떤 구조와 원리에 의해서 이루어지는지를 집중적으로 설명하는데 주안점을 두었다. 따라 www.yes24.com 해당 책을 보며 간단하게 요약하며, 디테일한 부분은 제외하였습니다.
hyo-ue4study.tistory.com/345 [CPP-effective] 4-4 함수에서 객체를 반환해야 할 경우에 참조자를 반환하려 하지말자. 이전에 작성한 글을 쓰고, 기존의 코드에 멀쩡하게 들어 있는 '값에 의한 전달' 부분을 '참조에 의한 전달'로 무작정 바꾸려고 하면 안 된다. 실제로 있지도 않은 객체의 참조자를 넘길 수도 있기 hyo-ue4study.tistory.com 이펙티브 c++를 작성하다가 등장하여 관련하여 찾아보았다. * 틀린 부분이 있을 수도 있습니다. 예제 클래스로 살펴보면 int num 멤버변수를 갖고 있는 클래스 T가 있다. class T { public: /*생성자*/ T(int a, string n) :num(a) , name(n) { cout
이전에 작성한 글을 쓰고, 기존의 코드에 멀쩡하게 들어 있는 '값에 의한 전달' 부분을 '참조에 의한 전달'로 무작정 바꾸려고 하면 안 된다. 실제로 있지도 않은 객체의 참조자를 넘길 수도 있기 때문이다. 예를 들어, 어떤 유리수를 나타내는 클래스가 있다고 치자. class Rational{ pulbic: Rational(int num = 0, int denominator = 1); //... private: int n, d; friend const Rational operator*(const Rational* lhs, const Rational* rhs); }; 해당 클래스의 operator*는 곱셉 결과를 값으로 반환하도록 되어있다. 값이 아닌 참조자를 반환할 수 있으면 비용 부담은 확실히 없을 것이..
C++에서 함수로부터 객체를 전달받거나, 함수에 객체를 전달할 때 '값에 의한 전달(Pass By Value)' 방식을 사용한다. 실제 인자의 '사본'을 통해 초기화되며, 어떤 함수를 호출한 쪽은 그 함수가 반환한 값의 '사본'을 돌려받는다. 사본을 만들어내는 원천이 바로 복사 생성자이다. 이 점 때문에 '값에 의한 전달'이 고비용의 연산이 된다. 어떤 클래스 A와 A를 상속받는 클래스 B 두 개가 있다고 할 때, 어떤 함수를 호출하려고 한다. B myB; bool DoSomething(B ref); B 클래스를 값으로 전달받는 함수가 있으면, myB를 매개변수 ref로 초기화시키기 위해 복사 생성자가 호출된다. 게다가 ref는 DoSomething함수가 끝나면서 소멸된다. 이렇게 되면 총 B클래스의 복..
C++에서 새로운 클래스를 정의한다는 것은 새로운 타입 하나를 정의하는 것과 같다. 단순히 클래스 설계를 하는것이 아니라 타입 설계를 한다고 생각하니 더 대단한 것 같다(?). 함수와 연산자를 오버로드하고, 메모리 할당 및 해제를 제어하며, 객체 초기화 및 종료 처리를 정의하는 작업 등 신경 써야 할게 많아지기도 한다는 것이다. 좋은 클래스를 설계한다는 것은 좋은 타입을 설계하는 것이기도 한데, 마냥 쉽기만 하지는 않을 것이다. 1. 문법(syntax)이 자연스럽고, 2. 의미구조(sematics)가 직관적이며, 3. 효율적인 구현이 한 가지 이상 해야 하는데, 고민 없이 클래스 정의를 했다가는 이 중 한가지도 못할 수도 있다. 심지어 멤버 함수조차도 어떻게 선언되었느냐에 따라 수행성능이 달라진다. 고려..
인터페이스는 만리장성을 쌓는 접선 수단입니다. 이상적으로 어떤 인터페이스를 어떻게 써 봤는데 결과 코드가 사용자가 생각한 대로 동작하지 않는다면 그 코드는 컴파일되지 않아야 되는 게 맞다. 반대로 어떤 코드가 컴파일이 되면 사용자가 원하는 대로 동작해야 하는 것이다. '제대로 쓰기엔 쉽고 엉터리로 쓰기에 어려운' 인터페이스를 개발하려면 우선 사용자가 저지를만한 실수의 종류를 미리 생각해봐야 한다. 예를 들어 날짜를 나타내는 어떤 클래스에 넣을 생성자를 설계하고 있다고 가정하자. class Date{ public: Date(int month, int day, int year); //... }; 별 문제가 없을 것 같지만, 매개변수의 순서가 잘못될 여지가 있다. Date d1(21, 4, 2021); //월..
어떤 동적으로 할당한 Player객체에 대해 어떤 처리를 함수는 하나가 있다고 가정하자. void doSomethingPlayer(shared_ptr p,int someValue) { //... } 그리고 어떤 값을 반환하는 함수가 있다고 하자. int GetSomething() { return 5; } 자원 관리 함수를 사용하는 게 좋긴 하니까 스마트 포인터(유니크 포인터)로 인자를 받고 있다. 이렇게 만든 함수를 사용해보려 했으나 int main() { doSomethingPlayer(new Player, GetSomething()); //error! return 0; } 컴파일 에러가 난다. 스마트포인터 생성자는 explicit로 선언되어 있기 때문에 'new Player' 표현식에 의해 만들어진 ..
string* str = new string[100]; //.. delete str; 얼핏 보면 맞는 것 같지만 str이 가리키는 100개의 string 객체들 가운데 99개는 정상적인 소멸을 거치지 못할 가능성이 크다. new 연산자를 사용해서 표현실을 꾸미게 되면(어떤 객체를 동적 할당하면,) 두가지의 내부 동작이 진행된다. 1. 메모리가 할당된다.(operator new 라는 이름의 함수가 쓰인다.) 2. 할당 된 메모리에 대해 한 개 이상의 생성자가 호출된다. 반대로 delete 표현식을 사용하는 경우도 두 가지의 내부 동작이 진행된다. 1. 기존에 할당된 메모리에 대해 한개 이상의 소멸자가 호출된다. 2. 그 후 메모리가 해제된다.(operator delete라는 이름의 함수가 쓰인다.) del..
이전에 팩토리함수와 같이 예를 들어 함수를 호출한 결과(포인터)를 담기 위해 스마트 포인터를 사용할 수 있었다. class Player { public: //... int GetHP() const { return 1; } }; Player* CreatePlayer() { return new Player; }; int main() { std::shared_ptr player01(CreatePlayer()); return 0; } 여기서 이제 스마트포인터로 만든 player01 객체를 사용하는 전역 함수가 생겼다고 치자. int GetPlayerHP(const Player* p) { return p->GetHP(); } 위에서는 hp정보를 예로 들고, int main() { shared_ptr player0..
#include #include // 크기별로 정수 자료형이 정의된 헤더 파일 int main() { int8_t num1 = -128; // 8비트(1바이트) 크기의 부호 있는 정수형 변수 선언 int16_t num2 = 32767; // 16비트(2바이트) 크기의 부호 있는 정수형 변수 선언 int32_t num3 = 2147483647; // 32비트(4바이트) 크기의 부호 있는 정수형 변수 선언 int64_t num4 = 9223372036854775807; // 64비트(8바이트) 크기의 부호 있는 정수형 변수 선언 // int8_t, int16_t, int32_t는 %d로 출력하고 int64_t는 %lld로 출력 printf("%d %d %d %lld\n", num1, num2, num3, n..
예를 들어서 뮤텍스(mutex)클래스를 만들어서 사용한다고 하자. 뮤텍스 잠금을 관리 하는 클래스를 관리하는 클래스는 기본적으로 RAII 법칙을 따라 구성합니다. 소멸 시에 그 자원을 해제하는 것입니다. class Lock{ public: explicit Lock(Mutex* pm) : mutexPtr(pm) { lock(mutexPtr); //자원을 획득합니다. }; ~Lock() {unlock(mutexPtr); } //자원을 해제합니다. private: Mutex* mutexPtr; }; 이렇게 만든 클래스는 생성하고 해제가 좀 편해집니다. Mutex m; //... void DoSomething() { Lock m1(&m) //... } //벗어나며 자동으로 풀립니다. 이렇게 보면 아무런 문제가 ..
캐릭터의 정보가 있는 캐릭터 클래스가 있고 객체를 사용자가 얻어내는 용도로 팩토리 함수만을 쓰도록 만들어져 있다고 가정해봅시다. class Character{ //... Character* CreateCharacter(); //... }; 함수를 통해 얻어낸 객체를 사용할 일이 없어질때, 해당 객체를 삭제해야 할 쪽은 이 함수의 호출장비니다. 아래 임시 함수에서 그렇게 만들었다고 합시다. void DoSomething() { //... Character* newCharacter= Character::CreateCharacter(); //.. delete newCharacter; } 문제가 없어보이지만, 중간의 주석 부분에서 중간 return이나 예외처리 등 delete까지 닿지 않게되면 메모리누수(mem..