묻공러
'C++/[루키스] Modern C++' 카테고리의 글 목록

C++/[루키스] Modern C++

C++/[루키스] Modern C++

[MC++] 스마트 포인터 (Smart pointer)

스마트 포인터는 포인터를 알맞은 규약에 따라 관리하는 객체이며 포인터를 래핑해서 사용한다 스마트 포인터의 종류에는 shared_ptr, weak_ptr, unique_ptr 등이 있다 shared_ptr의 간단 내부 동작원리는 아래와 같다 class Knight { public: Knight() {} ~Knight() {} void Attack() { if (mTarget) mTarget->mHp -= mDamage; } public: int mHp = 100; int mDamage = 10; Knight* mTarget = nullptr; }; class RefCountBlock { public: int mRefCount = 1; }; template class SharedPtr { public: Sh..

C++/[루키스] Modern C++

[MC++] Lambda

함수 객체를 이용한 기존 방식과 람다를 사용하는 방식을 비교하며 차이점과 람다의 장점을 알아보자 기존에 함수객체를 이용하는 방식은 아래와 같았다 enum class Rarity { Common, Rare, Unique, }; enum class ItemType { None, Armor, Weapon, Jewerly, Consumable, }; class Item { public: Item() { } Item(int itemId, Rarity rarity, ItemType type) : mItemId(itemId) , mRarity(rarity) , mType(type) { } public: int mItemId = 0; Rarity mRarity = Rarity::Common; ItemType mType..

C++/[루키스] Modern C++

[MC++] 전달 참조 (Forwarding reference)

기존에는 보편 참조(universal reference)라고 불렸는데 c++ 17을 통해 전달 참조(forwarding reference)로 불리게 되었다 전달 참조를 배우기 전, 오른 값 참조를 다시 복습하면 아래처럼 동작했다 class Knight { public: Knight() {}// 기본 생성자 Knight(const Knight&) {}// 복사 생성자 Knight(Knight&&) noexcept {}// 이동 생성자 }; void Test_RValueRef(Knight&& k)// 오른값 참조 { } int main() { Knight k1; //Test_RValueRef(k1);// 왼값은 받아주지 않음 Test_RValueRef(std::move(k1));// 캐스팅을 통해 왼값을 오..

C++/[루키스] Modern C++

[MC++] 오른 값 참조 (Rvalue reference)와 std::move

왼 값(L value) : 단일식을 넘어서 계속 지속되는 개체 오른 값(R value) : L value가 아닌 나머지 ex. 임시 값, 열거형, 람다, i++ 등... 아래를 통해 다양한 참조 방식과 그에 따른 차이점을 살펴보자 class Knight { public: public: int mhp = 100; } void TestKnight_Copy(Knight knight) {} void TestKnight_LValueRef(Knight& knight) {} void TestKnight_ConstLValueRef(const Knight& knight) {} void TestKnight_RValueRef(Knight&& knight) {} int main() { Knight k1; TestKnight_..

C++/[루키스] Modern C++

[MC++] override, final

여기서 잠깐, 오버로딩은 함수 이름의 재정의 ex. 인자의 타입 및 개수에 따라 같은 이름의 함수를 재정의 오버라이딩은 상속관계의 클래스 내에서 함수 재정의 ex. Player 클래스의 Attack 함수, Knight 클래스의 Attack 함수 아래와 같이 가상함수를 오버라이드 하는 경우 override를 붙여줌으로써 오버라이드된 함수라는 사실을 가독성 측면에서 증가시킨다 맨 처음 가상함수를 정의하는 부모 클래스에는 override를 붙일 수 없으며 이를 받는 자식들의 가상함수에 override를 붙인다 class Creature { public: virtual void Attack() { } } class Player : public Creature { public: virtual void Attack..

C++/[루키스] Modern C++

[MC++] delete

클래스 내 함수를 막기 위해서는 아래와 같이 private으로 막아주면 된다 class Knight { public: private: void operator=(const Knight& k) { } private: int mhp = 100; } int main() { Knight k1; Knight k2; //k1 = k2;// 복사 연산자 작동 불가 } 하지만 friend를 이용하면 이를 간접적으로 뚫을 수 있다 class Knight { public: private: void operator=(const Knight& k) { } friend class Admin; private: int mhp = 100; }; class Admin { public: void CopyKnight(const Knigh..

C++/[루키스] Modern C++

[MC++] enum class

enum (unscopped) enum PlayerType { PT_None, PT_Knight, PT_Archer, } 범위가 없고 전역에서 사용할 수 있기 때문에 중복되는 이름이 사용불가하며 이를 막기 위해 'PT_'와 같은 용어를 앞에 붙여서 사용한다 enum class (scopped) enum class ObjectType { Player, Monster, Projectile, } 범위가 정해져있기 때문에 중복되는 이름도 사용 가능하다 그리고 아래처럼 암묵적인 변환이 금지되어 있어 약간의 불편함이 장점, 단점으로 작용한다 enum class ObjectType { Player, Monster, Projectile, } double value = static_cast(ObjectType::Play..

C++/[루키스] Modern C++

[MC++] using

using은 typedef의 단점을 해결한 버전이다 typedef __int64 id; using id2 = int; using의 장점 1) 직관성 typedef void (*MyFunc)(); using MyFunc2 = void(*)(); 2) 템플릿과 함께 사용 가능 template using List = std::vector; //template //typedef std::vector List2; // typedef는 템플릿 사용 불가 int main() { List li; li.push_back(1); } 물론, 아래와 같이 typedef을 간접적으로 사용해서 템플릿과 사용할 수도 있긴 하다 template struct List2 { typedef std::list type; } int main..

C++/[루키스] Modern C++

[MC++] nullptr

nullptr의 의미와 사용 이유 class Test { public: Test(int a) { } Test(void* ptr) { } Knight* FindKnight() { return nullptr; } } int main() { int ptr = NULL;// 예전 사용 방식 //1) 오동작 방지 Test(0);// Test(int a) 생성자 생성 Test(NULL);// Test(int a) 생성자 생성 Test(nullptr);// Test(void* ptr) 생성자 생성 //2) 가독성 Knight* knight = FindKnight(); if(knight == nullptr) {} } nullptr 구현 const class Knight { public: // 그 어떤 타입의 포인터와도..

C++/[루키스] Modern C++

[MC++] 중괄호 초기화 {}

일반적으로 초기화하는 경우는 ()를 사용하고 특히, 배열의 경우에서는 {}를 사용한다 추가적으로, 본 내용과는 큰 관련은 없지만 클래스에서의 복사 생성자와 대입 연산자의 차이와 함께 클래스에서의 (), {} 초기화를 알아보자 Knight k1; Knight k2 = k1;// 복사 생성자 Knight k3;// 기본 생성자 k3 = k1;// 대입 연산자 Knight k4(k3);// () 초기화 Knight k5{k3};// {} 초기화 다시 돌아와서, 중괄호 초기화를 도입함으로써 아래와 같은 장점이 있다 1) vector 등 container와 잘 어울린다 // 소괄호 초기화 vector v1(3, 1);// 3 capacity를 가지고 있고 1로 모두 초기화해라 // 중괄호 초기화 vector v2..