본문 바로가기
Script/Modern C++

[Modern C++] Chapter 10. 람다 (lambda)

by song.ift 2023. 5. 23.

GitHub : https://github.com/developeSHG/Modern-C/blob/a30dc0a22e2afcdb8ae81e9ca9e3f46fb125ab66/Modern%20C%2B%2B/Modern%20C%2B%2B/%EB%9E%8C%EB%8B%A4%20(lambda).cpp 

 

GitHub - developeSHG/Modern-C: Modern C++

Modern C++. Contribute to developeSHG/Modern-C development by creating an account on GitHub.

github.com

 

 


 

 

#include <iostream>
#include <vector>

using namespace std;

// 주제 : 람다(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 IsUniqueItem
        {
            bool operator()(Item& item)
            {
                return item._rarity == Rarity::Unique;
            }
        };

        // 클로저 (closure) = 람다에 의해 만들어진 실행시점 객체
        auto IsUniqueLambda = [](Item& item) { return item._rarity == Rarity::Unique; }; // 람다 표현식 (lambda expression)
        // auto IsUniqueLambda = [](Item& item) -> int { return item._rarity == Rarity::Unique; }; // 반환형을 int로 해줌.

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

        if (findit != v.end())
            cout << "아이템ID: " << findit->_itemid << endl;
    }

    // 함수 객체를 이용하면 내가 원하는 데이터를 저장해 이리저리 사용할 수 있는 장점이 있다.
    {
        struct FindItemByItemid
        {
            FindItemByItemid(int itemid) : _itemid(itemid)
            {

            }

            bool operator()(Item& item)
            {
                return item._itemid = _itemid;
            }

            int _itemid;
        };

        int itemid = 4;

        // [ ] 캡처(capture) : 함수 객체 내부에 변수를 저장하는 개념과 유사
        // 사진을 찰칵 [캡처]하듯... 일종의 스냅샥을 찍는다고 이해
        // 기본 캡처 모드 : 값(복사) 방식(=) 참조 방식(&)
        
        auto findByItemIdLambda = [=](Item& item) { return item._itemid == itemid; };

        auto findit = std::find_if(v.begin(), v.end(), FindItemByItemid(itemid));
        
        if (findit != v.end())
            cout << "아이템ID: " << findit->_itemid << endl;

        // 변수마다 캡처 모드를 지정해서 사용 가능 : 값 방식(name), 참조 방식(&name) 
        auto findByItem = [=, &itemid](Item& item) { return item._itemid == itemid; };

        // C++에서는 기본적으로 모든 애들을 값 방식으로 하거나 참조 방식으로 하는 것을 지양하라고 한다.
        // 내부적으로 꼼꼼이 살펴보지 않으면 어떤 데이터가 캡처되어 내부로 들어갔는지 알기가 힘들 수도 있다.
        // 반면, 하나하나 지정해주면 번거롭긴 하지만, 그럼에도 불구하고 코드 가독성이 높아지면서 확연히 데이터의 흐름을 알 수 있다.
        // 주소값 캡처는 조심해서 활용해야 한다.
    }

    // 물론, 값 캡처도 조심해야 하는 부분.
    {
        class Knight
        {
        public:
            auto ResetHpJob()
            {
                auto f = [this]()
                {
                    _hp = 200;
                    // 정확히 보면 this->_hp
                };

                return f;
            }

        public:
            int _hp = 100;
        };

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

        // k를 delete 하고 job을 타고 들어가보면 this의 메모리는 삭제된 걸로 볼 수 있다.
        // 그래서 hp를 건드리는 부분은 날라간 메모리를 건드리게 되면서 메모리 오염이 일어난다.
        // 당장 크래쉬도 안일어날수도 있어 언젠간 일어나는 크래쉬가 더욱 위험하게 만들 수 있다.

        // 설령 모든 캡처 자체를 값 복사 방식으로 만들더라도 모두 안전하게 동작한다는 보장은 할 수 없다는 것이다.
        // 그래서 모든 방식을 값 복사 방식 or 참조 방식으로 하는 걸 지양하라는 뜻
    }

    // 결론은 매번마다 함수나 구조체, 클래스 등등 만들어 인자와 함수를 저장하고 사용해야 하는 부분을
    // 단 두줄 내지 코드로 줄일 수 있는 편리성이 강력하다고 볼 수 있다. (가독성도 좋음)
    // [캡처](인자값) { TODO };

    return 0;
}

댓글