일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 스마트포인터
- dataasset
- stl
- C++최적화
- UELOG
- 강참조
- 애셋로드
- 약참조
- BFS
- C++
- map
- enumasByue
- moreeffectiveC++
- 언리얼엔진구조체
- 람다사용정렬
- 선택정렬
- 정렬
- 언리얼가비지컬렉터
- 데이터애셋
- 알고리즘
- UE4 커스텀로그
- unorder_map
- 자료구조
- 프로그래머스
- 정렬알고리즘
- UML관련
- 크리티컬섹션
- UE_LOG
- 람다
- 델리게이트
- Today
- Total
목록C & CPP/Effective C++ (25)
기억을 위한 기록들
이전에 팩토리함수와 같이 예를 들어 함수를 호출한 결과(포인터)를 담기 위해 스마트 포인터를 사용할 수 있었다. 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..
예를 들어서 뮤텍스(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..
객체지향 시스템 중 설계가 잘 된 것들을 보면, 객체를 복사하는 함수가 딱 둘만 있는 것을 알 수 있습니다. 그것은 바로 복사 생성자와 복사 대입 연산자입니다. 이 둘을 통틀어 복사함수라고 부른다. 이 둘은 컴파일러가 필요에 따라 만들어내기도 한다. 이렇게 컴파일러가 생성한 복사 함두는 비록 자동으로 만들어졌지만, 동작은 기본적인 요구에 아주 충실하다!. 빠짐없이 잘 복사한다. 그러나 기본적으로 만들어진것 말고 직접 선언한다는 것은, 기본 동작에 뭔가 마음에 안드는 것이 있다는 것인데, 직접 이런 복사함수들을 구현할 때 틀린 부분이 있더라도 컴파일러는 이런 부분들을 짚어 주지 않는다는 것이다. 예를 들어 어떤 객체를 대입하는데 직접 작성한 다음에 추후에 나중에 클래스에서 멤버변수라도 새로 추가하게 된다면..
자기대입(self assignment)란, 어떤 객체가 자기 자신에 대해 대입 연산자를 적용하는 것을 말합니다. class Widget{...}; Widget myWidget; myWidget=myWidget; 보통 위와같은 식을 말하는데 이외에도 a[i]=a[j]; //i와 j가 같을수도 있다. *px=*py; //자기대입 가능성이 아주 높다, px와 py가 가리키는 대상이 같아지면 여러곳에서 하나의 객체를 참조하는상태 즉 중복참조(aliasing)이라고 불린다. 이외에도 자식부모 클래스의 상속관계 있는 클래스 사이에서도 중복 참조는 일어 날수도 있다. class Base{..}; class Player : public Base {...}; void DoSomething(const Base& rb, P..
C++의 대입연산은 재미있는 성질이 있다. int x,y,z; x=y=z=15; //사실처럼 연결된다. 또 하나의 재미있는 특성으로 우측 연관(right-associative)연산 이라는 점이다. 즉, 위의 대입 연산 사슬을 분석하게 되면 x = ( y = ( z = 15)); 위와 같이 된다. 이렇게 대입 연삱이 사슬처럼 엮이려면 대입연산자가 좌변 인자에 대한 참조자를 반환하도록 구현되어 있을 것이다. 이런 구현은 일종의 관례로 클래스에서 대입연산자를 만들게 된다면 class Player{ pulbic: Player& operator=(const Player& rhs) { //..내용 return *this; } }; "좌변 객체의 참조자를 반환하게 만들자"라는 규악은 위에서 단순 대입형 말고도 모든 ..
이유는 2가지로 첫 번째는 호출 결과가 원하는 대로 돌아가지 않고, 두 번째로는 원하는 대로 돌아간다고 해도 뭔가 굉장히 이상할 것이다. 예를 들어 class Player { public: Player() { log(); } virtual void log() { cout
* 소멸자에서는 예외가 빠져나가면 안된다. 만약 소멸자 안에서 호출된 함수가 예외를 던질 가능성이 있다면, 어떤 예외이든지 소멸자에서 모두 받아낸 후에 삼켜버리든지 프로그램을 끝내든지 해야한다. * 어떤 클래스의 연산이 진행되다가 던진 예외에 대해 사용자가 반응해야 할 필요가 있다면, 해당 연산을 제공하는 함수는 반드시는 보통의 함수(즉, 소멸자가 아닌 함수)이어야 한다.
다형성을 가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자. class Character { public: Character() { cout
일부 멤버 함수들은 C++에서 클래스 안에 직접 선언해 넣지 않으면 컴파일러가 자동으로 선언해주도록 되어 있습니다. 바로. 1. 복사 생성자(copy constructor) 2. 복사 대입 연산자(copy assignment operator) 3. 소멸자(destructor) 4. 기본 생성자 (선언 해놓지 않았다면) 가 있습니다. 컴파일러가 만드는 함수의 형태는 모두 기본형이다. 모두 public 멤버이며 inline 함수입니다. class Player {}; 이렇게 선언한 클래스와 아래와 같이 선언한 클래스가 대동소이하다는 것입니다. class Player { public: Player() // 기본생성자 {} Player(const Player& rhs) //복사 생성자 {} ~Player() //..
초기화되지 않은 값을 읽도록 내버려 두면 정의되지 않은 동작이 그대로 흘러나오게 된다. 어떤 플랫폼의 경우 미초기화 객체를 읽기만 해도 프로그램이 서버리기도 한다. 기본 제공 타입으로 만들어진 비멤버 객체에 대해서 직접 초기화 int x = 0; //int의 직접 초기화 const char* text="Hello"; //포인터의 직접 초기화 double num; std::cin>>num; //입력스트림에서 읽음으로써 "초기화" 수행 이런 부분을 제외하면 나머지는 생성자로 귀결된다. 여기서 대입(assignment)과 초기화(initialization)를 헷갈리면 안 된다. 아래와 같이 해주고 있는 건 대입이다. class A { public: A(); private; int a; int b; } A::A..
const는 상수(constant)로 변하지 않는 값이다. -const가 *의 왼쪽에 있으면 포인터가 가리키는 대상이 상수. -const가 *의 오른쪽에 있으면 포인터자체가 대상이 상수. -const가 둘다 있으면 포인터자체와 포인터가 가리키는 대상 둘다 상수이다. int text = 5; int text2 = 7; const int* p1 = &text; //비상수 포인터 - 상수 데이터 //*p1 = 12; // 에러 -> 데이터 변경 불가 p1 = &text2; // 성공 -> 주소변경 int* const p2 = &text; //상수 포인터 - 비상수 데이터 *p2 = 8; //성공 ->데이터 변경 //p2 = &text2; // 에러 -> 주소변경불가 const int* const p3 = &t..