Notice
Recent Posts
Recent Comments
Link
오븐 노트
[C++] 람다 (lambda) 본문
#include <iostream>
using namespace std;
#include <vector>
#include <list>
#include <deque>
#include <map>
#include <set>
#include <algorithm>
// 람다(lambda) -> 함수 객체를 빠르게 만드는 문법
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;
};
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));
// 람다 = 함수 객체를 손쉽게 만드는 문법
// 람다 자체로 C++11에 '새로운' 기능이 들어간 것은 아니다.
{
struct FindItem
{
FindItem(int itemId, Rarity rarity, ItemType type)
: _itemId(itemId), _rarity(rarity), _type(type)
{
}
bool operator()(Item& item)
{
return item._itemId == _itemId && item._rarity == _rarity && item._type == _type;
}
int _itemId;
Rarity _rarity;
ItemType _type;
};
// 클로저 (closure) = 람다에 의해 만들어진 실행시점 객체
// auto isUniqueLambda = [](Item& item) { return item._rarity == Rarity::Unique; }; // 람다 표현식(lambda expression)
int itemId = 4;
Rarity rarity = Rarity::Unique;
ItemType type = ItemType::Weapon;
// [ ] 캡처(capture) : 함수 객체 내부에 변수를 저장하는 개념과 유사
// 기본 캡처 모드 : 값(복사) 방식(=) / 참조 방식(&)
//auto findByItemIdLambda = [&](Item& item) { return item._itemId == itemId; };
// 변수마다 캡처 모드를 지정해서 사용 가능 : 값 방식 (name), 참조 방식 (&name) // 기본 캡처 모드보다 해당 방식을 추천!!!
auto findByItem = [itemId, rarity, type](Item& item) // 실무에서는 방식을 통일하여 부호로 작성하는 방식을 지양하는것이 좋다(직접 하나하나 작성). 꼼꼼히 뜯어보지 않는다면, 어떤게 어디로 들어갔는지 확인하기 매우 어려워진다, 가독성 이슈
{ // 만약 &itemId 처럼 주소값을 넘기게 된다면, 해당 주소값은 더 이상 사용해서는 안되는 상황이 발생 할 수도 있기에 람다 캡처를 할 경우에는 굉장히 조심하여 사용하여야한다.
return item._itemId == itemId && item._rarity == rarity && item._type == type;
}; // 사실, 람다 객체를 외부로 넘기는게 아니라면 기본 캡처 모드로 설정한다고 크게 문제 될 부분은 없긴하다.
itemId = 10;
auto findIt = std::find_if(v.begin(), v.end(), FindItem(4, rarity, type)); // 람다를 일회성으로 사용하려면 내용 자체를 박아넣어도 되긴 한다
// 이러한 stl과 같이 마지막 인자로 functor나 predicate, 함수 포인터 등등을 받아주는 형태에서는 무조건 lambda와 함께 동작하도록 하는것이 코드 가독성에도 좋고 작업 속도도 훨씬 빨라진다
if (findIt != v.end())
cout << "아이템ID: " << findIt->_itemId << endl;
}
{
class Knight
{
public:
auto ResetHpJob()
{ // 람다 자체는 타입에 대한 이름이 지어지지 않다보니 뱉어줄 때 어떤 형식으로 해야할지 매우 애매한데 auto(자동추론) 활용.
auto f = [this]() // 사실상 여기서 []는 [this]와 같음 / this 넣어준 이유는 가독성
{ // 모든 캡처 자체를 기본적으로 복사하는 것으로 만들었다고 하더라도 "모든것이 안전하게 동작한다는 보장은 절대없다!"
this->_hp = 200; // 어떠한 클래스 내부에 존재하는 함수에서는 멤버 변수에 접근 할 경우, 항상 this포인터를 이용하여 접근하고 있는것. 때문에 생략 가능
};
return f;
}
public:
int _hp = 100;
};
class Functor
{
public:
Functor(Knight* k) : _knight(k)
{
}
void operator()()
{
_knight->_hp = 200;
}
public:
Knight* _knight;
};
Knight* k = new Knight();
auto jop = k->ResetHpJob(); // 해당 jop 자체는 함수 객체이다 보니, 원할 때 실행 할 수 있음
delete k; // this->_hp = 200; 부분에서 이미 날아간 메모리를 건드리고 있다. 메모리 오염
jop();
}
// lambda 기본 형태 : []() {} : [캡처(functor에 내부 변수로 저장할 변수들을 복사할지, 참조값으로 넣을지 지정](인자값) { 구현부 }
return 0;
}
[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문 - 인프런 | 강의
C++ 카테고리의 글은 인프런 Rookiss님의 강의를 공부하며 정리하는 내용입니다.
이미 알고 있는 내용도 다시 정리 되어있을 수 있습니다.
모든 글은 제가 공부하기 위해 작성합니다.
'Develop > C++' 카테고리의 다른 글
[C++] 스마트 포인터 (smart pointer) (0) | 2024.01.04 |
---|---|
[C++] 전달 참조 (forwarding reference) (0) | 2024.01.02 |
[C++] 오른값 참조 (rvalue reference) (0) | 2023.12.30 |
[C++] override, final (0) | 2023.12.28 |
[C++] delete(삭제된 함수) (0) | 2023.12.13 |