原文:
https://devblogs.microsoft.com/oldnewthing/20190104-00/?p=100635
看到这个技巧,比较有意思,特翻译一下:
You may want to capture your this pointer into a C++ lambda, but that captures the raw pointer. If you need to extend the object’s lifetime, you will need to capture a strong reference. For plain C++ code, this would be a std::shared_ptr. For COM objects, this is usually some sort of smart pointer class like ATL::CComPtr, Microsoft::WRL::ComPtr, or winrt::com_ptr.
有时想在C++ lambda表达式中捕获this指针, 但是它捕获的是raw指针。如果需扩展对象的生存期,需要捕获它的一个强引用。对于纯粹C++代码来说,需使用std::shared_ptr。对于COM对象,通常是类似ATL::CComPtr, Microsoft::WRL::ComPtr或winrt::com_ptr等智能指针类。常规在lambda中使用智能针的见下:
// std::shared_ptr
auto callback = [self = shared_from_this()]() {
self->DoSomething(self->m_value);
self->DoSomethingElse();
};
// WRL::ComPtr
auto callback = [self =
Microsoft::WRL::ComPtr<ThisClass>(this)]() {
self->DoSomething(self->m_value);
self->DoSomethingElse();
};
// ATL::CComPtr
auto callback = [self =
ATL::CComPtr<ThisClass>(this)]() {
self->DoSomething(self->m_value);
self->DoSomethingElse();
};
// winrt::com_ptr
template<typename T>
auto to_com_ptr(T* p) noexcept
{
winrt::com_ptr<T> ptr;
ptr.copy_from(p);
return ptr;
}
auto callback = [self = to_com_ptr(this)] {
self->DoSomething(self->m_value);
self->DoSomethingElse();
};
每一个类变量都要带上self,是不是很累赘?
A common pattern for the “capture a strong reference to yourself” is to capture both a strong reference and a raw this. The strong reference keeps the this alive, and you use the this for convenient access to members.
针对"自行捕获强引用"比较常见的模式是同时捕获一个强引用和一个raw this指针。强引用起生存期扩展保活作用,this指针方便访问成员变量。
// std::shared_ptr
auto callback = [lifetime = std::shared_from_this(this),
this]() {
DoSomething(m_value); // was self->DoSomething(self->m_value);
DoSomethingElse(); // was self->DoSomethingElse();
};
// WRL::ComPtr
auto callback = [lifetime =
Microsoft::WRL::ComPtr<ThisClass>(this),
this]() {
DoSomething(m_value); // was self->DoSomething(self->m_value);
DoSomethingElse(); // was self->DoSomethingElse();
};
// ATL::CComPtr
auto callback = [lifetime =
ATL::CComPtr<ThisClass>(this),
this]() {
DoSomething(m_value); // was self->DoSomething(self->m_value);
DoSomethingElse(); // was self->DoSomethingElse();
};
// winrt::com_ptr
auto callback = [lifetime = to_com_ptr(this),
this]() {
DoSomething(m_value); // was self->DoSomething(self->m_value);
DoSomethingElse(); // was self->DoSomethingElse();
};
I like to give the captured strong reference a name like lifetime to emphasize that its purpose is to extend the lifetime of the this pointer. Otherwise, somebody might be tempted to “optimize” out the seemingly-unused variable.
在这里我把强引用指定名字为"lifetime"是为了强调它的意图是扩展this指针的生存周期。否则有些人可能会把这个看似无用的变量给优化掉。