天天看点

C++中在lambda表达式中使用this指针的技巧

作者:Leonard李

原文:

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指针的生存周期。否则有些人可能会把这个看似无用的变量给优化掉。