ROS2를 공부하면서 이 부분이 잘 몰라서 헤매었다...
스마트 포인터와 람다 함수가 얽혀있는 부분에서 이해가 안되서 쩔쩔 매었다.
GitHub - ros2/demos
Contribute to ros2/demos development by creating an account on GitHub.
github.com
일단 요지는.. 아래 코드에서 weak_ptr이 뜬금없이 들어가있는 거다.
std::weak_ptr<std::remove_pointer<decltype(pub_.get())>::type> captured_pub = pub_;
왜 끈금없이 weak_ptr로 할까? 뭔가 람다 함수 내부에서 순환참조되는 부분이 생기는 건가...
물론 람다 함수를 써볼 일도 없어서 람다가 어색하다.
그리고 뭔가 코드가 더 혼잡스럽게 보이긴하는데.. 단순해지는 장점은 있으니까
floating.io | Lambda + shared_ptr<> = memory leak
The Z-Wave interface I’m working on is an inherently asynchronous beast. Callbacks abound, and the use of lambda functions makes that much easier to deal with. This fact led me to select C++11 as the language standard for the project. And then I added au
floating.io
https://floating.io/2017/07/lambda-shared_ptr-memory-leak/
답은 해뤼님이 보내주신 위의 블로그에서 찾을 수 있었다.
요약하자면, lamda function에 변수를 capture 하게 되면 새로운 개체를 생성하게 되고 람다 함수는 하나의 멤버 함수가 되고, capture 변수도 멤버 변수가 됩니다. 그렇기 때문에 shared_ptr 변수를 넣게 되면, 기존 shared_ptr과 capture shared_ptr이 서로를 참조하게 됩니다. 이러면 shared_ptr이 서로를 참조하는 문제가 있기 때문에, weak_ptr을 사용해야합니다.
추가적으로 chatgpt 선생님 답변(동일 내용..)
람다 함수가 값으로 std::shared_ptr을 캡처하면 공유 포인터의 복사본을 만듭니다. 이 사본은 공유 객체의 참조 횟수를 증가시켜 객체 소유자가 한 명 더 있음을 나타냅니다.
람다 함수가 캡처하는 개체의 멤버 변수에 저장되고 해당 람다 함수가 개체의 std::shared_ptr을 캡처하면 순환 종속성이 생성됩니다. 개체는 멤버 변수를 통해 람다 함수의 소유권을 가지며 람다 함수는 캡처된 std::shared_ptr을 통해 개체의 소유권을 갖습니다. 결과적으로 객체와 람다 함수는 여전히 서로에 대한 참조를 보유하고 있기 때문에 소멸될 수 없습니다.
이 순환 종속성은 std::shared_ptr의 참조 횟수가 0에 도달하는 것을 방지하므로 개체가 할당 해제되지 않아 메모리 누수가 발생합니다. 개체와 연결된 메모리는 더 이상 필요하지 않은 경우에도 해제되지 않습니다.
이 문제를 방지하려면 람다 함수에서 공유 객체를 캡처할 때 std::weak_ptr을 사용하는 것이 좋습니다. std::shared_ptr과 달리 std::weak_ptr을 캡처해도 참조 횟수가 증가하지 않습니다. 이를 통해 람다 함수는 소유권 의미 체계에 영향을 주거나 파괴를 방지하지 않고 개체를 관찰하거나 액세스할 수 있습니다.
std::weak_ptr을 사용하면 순환 종속성이 끊어져 개체와 람다 함수가 더 이상 필요하지 않을 때 적절하게 할당 해제될 수 있습니다. 이렇게 하면 메모리 누수를 방지하고 개체 수명을 올바르게 관리할 수 있습니다.
블로그와 gpt를 요약해보면
람다 함수에서 순환종속성 방지를 위해서 weak_ptr을 사용하라.