c++ lambda 捕获这个概念

c++ lambda capture this concept

用C++编程,可能我的脑子还停留在90年代,有些概念绕不开,请大家帮帮我。

使用 gtkmm 进行开发,遇到了一些多线程示例,如下所示

class ExampleWorker {

public:
    void do_work(ExampleWindow* caller);
private:
    mutable std::mutex m_Mutex;
};

ExampleWindow::ExampleWindow(){
    ExampleWorker m_Worker;
    std::thread* m_WorkerThread;

void ExampleWindow::on_start_button_clicked() {
    if (blablabla){
        blablabla
    } else {
        // Start a new worker thread.
        m_WorkerThread = new std::thread(/////////////lambda function
            [this]    // <==== let this this be "this-A"
            {
                m_Worker.do_work(this);     // let this this be "this-B"
            }///////////////end of lambda function /////////////
        );
    }

我无法理解的主要是 lambda 部分。所以首先 lambda 概念对我来说很新,我在 C++ 中查找 "capture" 的概念但没有找到太多,所以我最好的猜测是,在这种情况下,它允许我 "capture" 根据文档,返回的“[this]”似乎是 [this] captures the this pointer by value,指向 worker 的指针被转换为线程指针,因为 worker 包含互斥量。

然而我不明白的是,对我来说,"this-B" 似乎表明 "this" 正在将 ExampleWindow 对象本身传递给函数,正如 Worker class 它应该将其调用者传递给它; whislt "this-A" 似乎能够引用工作线程本身。问题,这是否意味着 lambda 函数在这种情况下捕获 [this],取代了正常的 "this",后者引用 "this-B" 中的调用对象?

关于 lambda 的更多信息,另一个我一直难以理解的例子来自 boost asio。

//definition
void async_read_some(
const MutableBufferSequence & buffers,
ReadHandler handler);

// async_tcp_echo_server.cpp
class session  : public std::enable_shared_from_this<session>{
private:
  void do_read()
  {
    auto self(shared_from_this());
    socket_.async_read_some(boost::asio::buffer(data_, max_length),
        [this, self](boost::system::error_code ec, std::size_t length) //<===this is where it is very troubling
        {
          if (!ec)
          {
            do_write(length);
          }
        });
  }

所以假设那部分是一个处理程序,为什么是它,或者它是 2 个函数?它会同时调用 this->do_write 和 self->do_write 吗?它们有何不同?在这种情况下,[this, self] / [this] / [self] 之间到底有什么区别?是第一个/self被执行了吗?

关于 lambda 的更多信息,它只是一种简化了 c++11 之前的某些内容的语法吗?有什么等价的 pre c++11 吗?或者它是否提供了一些新功能,例如在函数中访问一些以前无法访问的变量?抱歉,这似乎是微不足道的,但我想我通读了文档和其他一些在线文章并尝试但仍然未能掌握整个概念。

对我来说,最初理解 lambda 对我这样看待它们很有帮助。

struct <closure>
{
    <something> operator()(<params>) const { ... <function>; }

    <init-capture-as-members>
};

所以

[someInt](double a, double b) { return 5; }

struct <closure>
{
    int operator()(double a, double b) const { return 5; }        
    int someInt;
};

捕获列表中的所有内容都像 "members",当您执行 lambda 时,您调用 operator()

它更复杂(甚至有 const 和 mutable 等)但它只是一个简单的抽象。


现在针对您的具体问题:

this 是指向您所在对象的指针。因此它不是指向 std::thread 对象的指针,而是指向 ExampleWindow 对象的指针。

捕获列表中的

this也有一种特例。 当您将 [this] 添加到捕获列表时,您 "allow" lambda 将调用当前对象的所有内容。它还允许您在不使用 this-> 作为前缀的情况下使用成员函数。

所以你的调用 do_write(...) 可以看作 this->do_write(...)

self 只是一个共享指针,因此它将像其他所有捕获的对象一样对待。您必须显式调用 self->... 才能对其执行任何操作。我假设这在 init-capture 中是必需的,因此只要线程运行,对象就会保持活动状态。仅在 init-capture 中使用 this 不会增加引用计数,因此您可能会在不调用 do_write 时意外删除对象。