1. 람다(lambda)
함수 객체(함수처럼 작동하는 객체)를 빠르게 만드는 문법.
아이템 id, 희귀도, 타입을 받는 클래스를 만든다.
enum class ItemType
{
None,
Armor,
Weapon,
Jewelry,
Consumable
};
enum class Rarity
{
Common,
Rare,
Unique
};
class Item
{
public:
Item() {}
Item(int itemid, Rarity rarity, ItemType type)
: _itemid(itemid), _rarity(rarity), _type(type)
{
}
public:
int _itemid = 0;
Rarity _rarity = Rarity::Common;
ItemType _type = ItemType::None;
};
그리고 새로운 벡터를 만들어서 4개의 아이템을 push_back 한다.
int main()
{
vector<Item> v;
v.push_back(Item(1, Rarity::Common, ItemType::Weapon));
v.push_back(Item(2, Rarity::Common, ItemType::Armor));
v.push_back(Item(3, Rarity::Rare, ItemType::Jewelry));
v.push_back(Item(4, Rarity::Unique, ItemType::Weapon));
}
이제 함수 객체(Functor ; 펑터)를 사용하여 특정 조건의 아이템을 찾아주는 기능을 구현해본다.
{// 특정 조건에 따라서 아이템 찾기
struct IsUniqueItem
{
bool operator()(Item& item)
{
return item._rarity == Rarity::Unique;
}
};
auto findIt = std::find_if(v.begin(), v.end(), IsUniqueItem());
if (findIt != v.end())
cout << findIt->_itemid;
}
}
람다를 사용하여 위의 함수 객체를 간단하게 구현할 수 있다.
[](Item& item) {return item._rarity == Rarity::Unique;};
- 특징
(1) 컴파일러가 함수 객체를 적당한 이름으로 사용한다.
(2) 반환 형식을 컴파일러가 판단하여 적용한다.
(여기에서는 boolean으로 반환한다)
auto IsUniqueLambda = [](Item& item)
{return item._rarity == Rarity::Unique;};
또는 펑터를 임시적으로 사용하겠다고 하면 findIt 함수 안에 그대로 쓸 수도 있다.
auto findIt = std::find_if(v.begin(), v.end(),
[](Item& item) {return item._rarity == Rarity::Unique;});
(3) 펑터의 데이터를 저장할 수 있다는 장점도 그대로 가지고 있다.
- 클로저(Closure)
람다에 의해 만들어짐 실행 시점의 객체
2. 캡쳐(Capture)
람다 표현식 내부에서 외부 변수를 사용할 수 있게 함.
- 기본 캡쳐 모드
(1) 값(복사) 방식
int itemId = 3;
auto findByItemIdLambda = [=](Item& item)
{
return item._itemid == itemId; // itemId = 3의 값을 사용
};
(2) 참조 방식
int itemId = 3;
auto findByItemIdLambda = [&](Item& item)
{
return item._itemid == itemId; // itemId의 주소값을 사용
};
itemId = 10;
auto findIt = std::find_if(v.begin(), v.end(), findByItemIdLambda());
// itemid = 10인 아이템을 찾음
- 혼합 캡쳐 ; 변수마다 캡처 모드를 다르게 지정하기
auto findByItemIdLambda = [&itemId, rarity, type](Item& item)
{
return item._itemid == itemId && item._rarity == rarity && item._type == type;
};
코드 가독성을 높이기 위해 혼합 캡쳐를 사용하는 것이 권장된다.
2. 람다 표현식을 사용할 때 발생할 수 있는 문제
class Knight
{
public:
auto ResetHpJob()
{
auto f = [this]()
{
this->_hp = 200;
};
return f;
}
public:
int _hp = 100;
};
이렇게 클래스의 멤버 함수를 만들고 이후에 객체를 생성한다.
Knight* k = new Knight();
auto job = k->ResetHpJob();
delete k;
job();
위에서 처럼 새롭게 동적 할당을 통해 Knight의 객체를 생성하고 내부 변수를 사용 후에 객체를 제거한 이후에
또 멤버 함수에 접근하게 되면 엉뚱한 메모리 영역을 수정하는 문제가 발생할 수 있다.
여기에서는 변수 f에 람다 표현식을 사용할 때 캡쳐 모드에 this 포인터를 명시해주어서 문제를 빠르게 해결할 수 있으나
그렇지 않으면 문제를 찾기 어려워진다.
'기초 C++ 스터디 > 모던 C++' 카테고리의 다른 글
10-10. 스마트 포인터 (0) | 2023.06.26 |
---|---|
10-8. 전달 참조 (forwarding reference) (0) | 2023.06.22 |
10-7. 오른값 참조(Rvalue Reference) (0) | 2023.06.22 |
10-6. override, final (0) | 2023.06.20 |
10-5. delete - 삭제된 함수 (0) | 2023.06.20 |