프로그래밍/C++

#68. 람다 (lambda)

코딩하는상후니 2022. 7. 22. 22:45

 

 


 
*람다 표현식 ( lambda expression )
 
[ 캡처 ] ( 매개변수 ) { 구현부 }   => '리턴값 자동 추론'
[ 캡처 ] ( 매개변수 ) -> 리턴값 { 구현부 }
vector<Item> vec;
auto findIt = std::find_if(vec.begin(), vec.end(),  
	[ ](Item& item) 
	{ 
		return item.Rarity == Rarity::Unique; 
	});

 

 

 

 

*[ ] 캡처 ( capture ) 
 
=> 함수 객체 내부에 변수를 저장하는 개념과 유사
 
 
* [&]  :  call-by-reference 와 유사
=> 외부의 모든 변수들의 주소를 가져온다.
int a = 4; 
auto Changed = [&]() { a = 5; };
=> 참조를 사용할 땐 값이 바뀔 수 있음을 인지해야함. 항상 조심 ( 주소값 참조 )
 
 
* [=]  :  call-by-value 와 유사
=> 외부의 모든 변수들의 값을 가져온다.
int a = 4;  
auto IsCheck = [=]() { return a == 1; };
a = 10;

 

 

 

 

 

*값 캡처는 언제 값이 복사가 되는가 ??
int v = 42; 
auto func = [=] { cout << v << endl; }; 
v = 8; 
func();
=> 42
=> 클로저 객체가 '생성되는 시점' 에서 v 의 값을 가져온다.
=> 또한, 값 캡처가 된 값들은 자동적으로 'const' 가 된다. ( 상수화 )
 
 
*const 된 값들을 바꿀 수 있을까 ??
=> mutable
int v = 42; 
auto func = [=] () mutable 
{ 
	v += 8; 
	cout << v << endl; 
}; 
func();
=> 실제 외부의 v 값은 바뀌지 않음.
 
 
 
* 변수마다 캡처모드를 지정해서 사용 가능.
int a = 1, b = 2, c = 3; 
int Sum = 0; 
auto Changed = [&a, b, c, &Sum]() 
{ 
	a = 10; 
	Sum = b + c; 
};
=> 기본적인 값, 참조 ( [&, = ] ) 캡처모드는 지양.
=> 사용할 변수들 각각 캡처모드를 지정해서 사용.

 


 

*클래스 안에서의 값 캡처
struct foo { 
  foo() : i(0) {} 
  void amazing() { 
    [=] { i = 8; }(); 
  } 
  int i;  
};

foo f; 
f.amazing(); 
cout << "f.i : " << f.i;
=> 클래스 안에서 [=] 하게 되면,
암묵적으로 클래스의 this 를 복사함으로써,
클래스 멤버변수 i 에 접근 가능하게 된다.

 

 

 

*캡처의 범위
int i = 8; 
auto f = [=]() { 
  int j = 2; 
  auto m = [&] { i /= j; }; 
  m(); 
  cout << "inner: " << i; 
}; 
f(); 
cout << " outer: " << i;
=> 캡처되는 변수들은 람다가 접근 가능한 위치에 있어야 함.
 
 
 
 
 
*클로저 ( closure ) => 람다에 의해 만들어진 실행시점 객체 ( isUniqueLambda )
class Player 
{ 
public: 
	Player() {} 
	~Player() {} 
	Player(const Player& other) 
	{ 
		Data = other.Data; 
		cout << "복사생성자" << endl; 
	} 
	Player& operator=(const Player& other) { cout << "복사대입연산자" << endl; } 
	int Data = 101; 
};


Player P1, P2, P3; 
int Sum = 0; 
auto SumPlayerData = [=, &Sum]() 
{ 
	Sum += P1.Data; 
	Sum += P2.Data; 
	Sum += P3.Data; 
}; 
SumPlayerData(); 
cout << Sum << endl;
=> 클래스 [ = ] 값 캡처 시,  복사생성자 호출

 

 


*결론
 
 
어떤 행동을 저장해 내가 원하는 시점에 제어하기 위해서,
함수포인터, functor 를 이용해 굉장히 많은 작업을 했어야했지만
람다식으로 인해 효율성 증가.
transform, for_each, find_if ... 등 C++ 의 다양한 기능에 접목시켜 활용 가능.
 
[ = ] , [ & ] 는 지양.
개별로 각기 캡처를 받아 사용하는 것이 바람직.
값이 어떻게 변하는지 항상 유의.
 

 

 


참고 링크

 

본 내용은 인프런의 루키스님 강의를 듣고 정리한 내용입니다.