개발 공부/코딩 공부

C++ 람다식

baby-t 2025. 9. 16. 10:01

## 람다식의 구조

람다식은 보통 이런 형태로 생겼습니다.

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

 

  1. [ ] (캡처 절, Capture Clause): 람다의 가장 큰 특징입니다. 람다 함수 바깥에 있는 변수를 안으로 "붙잡아와서" 사용할 수 있게 해주는 통로입니다.
    • [ ]: 아무것도 캡처하지 않음
    • [=]: 바깥의 모든 변수를 **값(복사)**으로 캡처
    • [&]: 바깥의 모든 변수를 참조로 캡처
    • [var]: var라는 변수만 값으로 캡처
    • [&var]: var라는 변수만 참조로 캡처
  2. () (매개변수, Parameter List): 일반 함수처럼 매개변수를 받는 곳입니다. 필요 없으면 생략 가능합니다.
  3. -> 반환타입 (Return Type): 함수의 반환 타입을 명시하는 부분인데, 대부분 컴파일러가 알아서 추론해주기 때문에 생략 가능한 경우가 많습니다.
  4. {} (함수 본문, Function Body): 실제 코드가 들어가는 부분입니다.

## 그래서 언제 사용할까요? (예시)

람다식은 특히 sort 같은 표준 라이브러리 알고리즘 함수와 함께 사용할 때 매우 유용합니다.

예시 1: std::sort와 함께 사용하기

아까 보았던 내림차순 정렬을 람다식으로 바꿔보겠습니다.

C++
 
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {3, 1, 4, 1, 5, 9};

    // 별도의 비교 함수나 greater<>() 없이
    // 세 번째 인자로 비교 로직을 담은 람다식을 바로 작성!
    std::sort(vec.begin(), vec.end(), [](int a, int b) {
        return a > b; // a가 b보다 크면 true -> 내림차순
    });

    for (int num : vec) {
        std::cout << num << " "; // 결과: 9 5 4 3 1 1 
    }
    std::cout << std::endl;

    return 0;
}

별도의 비교 함수를 만들 필요 없이 sort가 필요한 그 줄에서 바로 정렬 로직을 작성할 수 있어 코드가 훨씬 간결해집니다.

예시 2: 캡처 기능 활용하기

벡터의 모든 원소를 더하는 코드를 람다식으로 작성해 보겠습니다.

C++
 
#include <iostream>
#include <vector>
#include <numeric> // for_each

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    int sum = 0;

    // for_each는 각 원소에 대해 주어진 함수(람다)를 실행
    // [&sum]을 통해 바깥의 sum 변수를 참조로 가져와 값을 직접 더함
    std::for_each(numbers.begin(), numbers.end(), [&sum](int n) {
        sum += n;
    });

    std::cout << "합계: " << sum << std::endl; // 결과: 합계: 15

    return 0;
}

[&sum]을 통해 람다 함수 바깥에 있는 sum 변수에 접근해서 값을 수정하는 것이 핵심입니다.


캡처 자세한 예시

## 1. []: 아무것도 캡처하지 않음

가장 기본적인 형태로, 람다 함수는 바깥의 어떤 변수에도 접근할 수 없습니다. 오직 람다 함수 내부에서 정의된 변수나 매개변수만 사용할 수 있습니다.

C++
 
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    int value = 10;
    string message = "Hello";

    // value나 message에 접근하려고 하면 컴파일 에러 발생
    auto myFunction = []() {
        // cout << value << endl; // ERROR: 'value' is not captured
        cout << "I can't see outside variables." << endl;
    };

    myFunction();

    return 0;
}

핵심: 외부와 완전히 단절된, 독립적인 함수를 만들 때 사용합니다.


## 2. [=]: 값으로 캡처 (Capture by Value)

람다가 생성되는 시점에 바깥 변수들의 값을 복사해서 가져옵니다. 따라서 람다 내부에서는 복사된 값을 사용하며, 바깥의 원본 변수에는 영향을 주지 못합니다.

C++
 
#include <iostream>

using namespace std;

int main() {
    int apples = 10;

    // 람다 생성 시점의 apples(10)가 복사되어 람다 안에 저장됨
    auto countApples = [=]() {
        // 람다 안의 apples는 복사본이므로, 여기서 값을 바꿔도
        // 바깥의 apples는 변하지 않음
        // apples = 20; // ERROR: 값으로 캡처한 변수는 수정 불가
        cout << "Inside lambda, I have " << apples << " apples." << endl;
    };

    apples = 20; // 람다를 만든 후 원본 값을 변경

    cout << "Outside, I now have " << apples << " apples." << endl;
    
    // 람다 실행
    countApples(); // 결과: Inside lambda, I have 10 apples.

    return 0;
}

핵심: 람다를 만들 때의 **"스냅샷"**을 찍는 것과 같습니다. 람다 생성 이후에 원본 값이 바뀌어도 람다 안의 값은 그대로입니다.


## 3. [&]: 참조로 캡처 (Capture by Reference)

바깥 변수의 **"별명" 또는 "바로가기"**를 가져오는 것과 같습니다. 람다 내부에서 변수를 사용하면 실제 원본 변수에 접근하게 됩니다. 따라서 람다 안에서 값을 바꾸면 원본도 바뀝니다.

C++
 
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    int totalSum = 0;
    vector<int> numbers = {1, 2, 3, 4, 5};

    // [&]를 사용해 바깥의 totalSum에 직접 접근
    for_each(numbers.begin(), numbers.end(), [&](int num) {
        // 여기서 totalSum을 수정하면 바깥의 원본이 바뀜
        totalSum += num;
    });

    cout << "Total sum is: " << totalSum << endl; // 결과: Total sum is: 15

    return 0;
}

핵심: 람다를 통해 외부 변수를 직접 제어하고 싶을 때 사용합니다. 마치 리모컨으로 TV를 조작하는 것과 같습니다.


## 4. 특정 변수만 지정해서 캡처하기

전체를 캡처하는 [=]나 [&] 대신, 필요한 변수만 콕 집어서 캡처할 수도 있습니다.

  • [var]: var만 으로 캡처
  • [&var]: var만 참조로 캡처
  • [=, &var]: 기본적으로 값으로 캡처하지만, var만은 참조로 캡처
  • [&, var]: 기본적으로 참조로 캡처하지만, var만은 으로 캡처
C++
 
#include <iostream>

using namespace std;

int main() {
    int x = 100;
    int y = 200;

    // x는 값으로, y는 참조로 캡처
    auto selectiveCapture = [x, &y]() {
        // x = 101; // ERROR: x는 값으로 캡처되어 수정 불가
        cout << "x (by value): " << x << endl;
        
        y = 201; // OK: y는 참조로 캡처되어 수정 가능
        cout << "y (by reference): " << y << endl;
    };

    selectiveCapture();
    
    cout << "After lambda, original y is now: " << y << endl; // 결과: 201

    return 0;
}

핵심: 꼭 필요한 변수만, 필요한 방식으로 가져와서 코드의 의도를 명확하게 하고 실수를 줄일 수 있습니다.

 

 

## 핵심 요약

  • 람다식은 이름 없는 임시 함수다.
  • 필요한 곳에서 즉시 생성하여 사용하고 사라진다.
  • 코드를 간결하고 가독성 있게 만들어준다. (특히 알고리즘과 함께 쓸 때 👍)
  • [](캡처)를 통해 외부 변수에 접근하는 강력한 기능을 가지고 있다.

'개발 공부 > 코딩 공부' 카테고리의 다른 글

최대 공약수, 최소 공배수  (0) 2026.04.02
C++ 입출력  (0) 2025.09.15
프로그래머스 리스트 자르기  (0) 2025.09.13
c++ <limits>, const &auto  (0) 2025.09.03
복사와 함수 인자 전달 , 그리고 메모리  (0) 2025.09.03