C++프로그래밍/모던C++

람다

season97 2024. 10. 3. 11:03
728x90
반응형

개인적인 공부를 위해 포스팅 하는 글입니다.


▶ 람다 ◀

함수 객체를 빠르게 만드는 문법

람다 자체로 C++11에 새로운 기능이 들어간 것은 아니다

더보기

 

#실습 준비코드

#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;

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));
}

※ 임시 객체 만들어 넣어주는거라 지난 포스팅에서 다룬 R-Value참조가 내부적으로 되어있는 모습

 


# 람다가 나오기 전

struct IsUniqueItem
{
    bool operator()(Item& item)
    {
        return item._rarity == Rarity::Unique;
    }
};
std::find_if(v.begin(), v.end(), IsUniqueItem());

ㆍ 이런식으로 함수객체를 만들어줘서 넣어줬을것이다... 저 IsUniqueItem은 어쩌면 한번 쓰고 다시는 안쓸놈인데도 저렇게 함수를 만들어줘서 해야하는게 좀 귀찮다.

 

이럴 때 람다를 쓰자 

std::find_if(v.begin(), v.end(), [](Item& item) {return item._rarity == Rarity::Unique; });

ㆍ 위 코드와 같은 말이다. 이름이 없는 익명함수

 

[캡처목록](매개변수 목록) -> 반환타입 { 함수 본문 }

ㆍ 반환 타입은 생략 가능. 컴파일러가 추론해준다.

//[클로저] (closure) = 람다에 의해 만들어진 런타임 객체
auto IsUniqueLamda = [](Item& item) ->bool {return item._rarity == Rarity::Unique; };
std::find_if(v.begin(), v.end(), IsUniqueLamda);

ㆍ 이렇게도 넣어줄 수 있다.

 

 

# 캡처 영역을 보기 위해 한번 더 해보자 이번엔 아래경우

struct FindItemByItemId
{
    FindItemByItemId(int itemId) :_itemId(itemId)
    {

    }

    int _itemId;
    bool operator()(Item& item)
    {
        return item._itemId == _itemId;
    }
};
int itemId = 4;
auto findIt = std::find_if(v.begin(), v.end(), FindItemByItemId(itemId));
if (findIt != v.end())
{
    cout << "아이템 아이디 : " << findIt->_itemId << endl;
}

ㆍ 위 코드를 람다형식으로 바꿔봤다..

auto findByItemIdLamda = [=](Item& item) {return item._itemId == itemId; };

ㆍ 캡처모드는 값방식 ( = ), 참조방식( & ) 두가지가 있다. 말 그대로 스냅샷을 찍는다고 이해하자.

ㆍ 값방식 참조방식은 뭐 알고있는 그대로다. 복사할건지,원본객체 할건지

  auto findByItemIdLamda = [=](Item& item) {return item._itemId == itemId; };
  auto findIt = std::find_if(v.begin(), v.end(), findByItemIdLamda);
  if (findIt != v.end())
  {
      cout << "아이템 아이디 : " << findIt->_itemId << endl;
  }

ㆍ 동일한 결과가 실행된다.

 auto findByItemIdLamda = [itemId, &rarity](Item& item) {return item._itemId == itemId; };

ㆍ 이런식으로 전체가 아니라 각각 변수마다도 캡처를 지정해 줄 수도 있다.

 

ㆍ  C++에서는 기본 캡처모드(전체캡처) 를 사용하지 않는것을 권고한다.  그러므로 어떤것을 캡처할거고, 값으로할건지 참조로 할건지 꼭 정해주도록 하자.

ㆍ 전체 캡처를 남발하면 주소가 해제되었을때.... 예상하지 못한 버그가 발생할 경우가 있을 수 있겠다. .

class Knight
{
public:
    auto ResetHpJob()
    {
        auto f = [this]() 
            {
                this->_hp = 200;
            };
        return f;
    }

public:
    int _hp;
};

Knight* k = new Knight();
auto job = k->ResetHpJob();
delete k;
job();

ㆍ 맨아래 두줄... 저 상황이 진짜위험하다. 지금 당장 프로그램이 터지지 않아도 메모리가 계속 오염될거다

728x90
반응형