2016-10-12 3 views
2

Программирование с использованием C++, возможно, мой разум все еще застрял в 90-х годах, не может обойти некоторые концепции, пожалуйста, помогите мне.C++ lambda захватить эту концепцию

Так развивалась, используя 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 ///////////// 
     ); 
    } 

Главное у меня возникли проблемы понять лямбда часть. Итак, в первую очередь концепция лямбда для меня совершенно новая, искала концепцию «захвата» на C++, но не нашла многого, поэтому я думаю, что в этом случае она позволяет мне «захватить» " [this] ", который был возвращен, согласно документу, выглядит как [this] captures the this pointer by value, указатель на работника, заброшенный как указатель потока, поскольку рабочий содержал мьютекс.

Однако я не понимаю, что для меня «это-B», по-видимому, указывает, что «это» передает объект ExampleWindow непосредственно функции, как определено классом Worker, что он должен быть передавая в нее своего вызывающего; whislt «this-A», похоже, может ссылаться на сам рабочий поток. Вопрос, означает ли это, что функция лямбда-функции захватывает [это] в этом случае, вытесняет нормальное «это», которое относится к вызывающему объекту, как в «this-B»?

И немного больше о лямбда-веществе, еще один пример, который я всегда старался понять, исходил от взрыва асио.

//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]? Это то, что первый из этого/сам выполняется?

Подробнее о лямбда, это только синтаксис, который упростил что-то в pre C++ 11? есть ли что-то эквивалентное pre C++ 11? Или он предоставляет новые функции, такие как доступ к некоторой ранее недоступной переменной в функции? Извините, что казалось тривиальным, но я думаю, что прочитал документы и некоторые другие онлайн-статьи и попытался, но все же не смог понять всю концепцию.

ответ

6

Для меня понимание лямбда вначале помогло, когда я посмотрел на них вот так.

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; 
}; 

все в списке захвата, как «члены» и при выполнении лямбды вы называете operator()

Это более сложное (даже имеет сопзЬ и изменяемые т.д., .), но это просто абстракция.


Так что теперь для ваших конкретных задач:

this является указателем на объект, вы находитесь в Таким образом, это не указатель на std::thread объекта, но к ExampleWindow объекта..

this в списке захвата также имеет вид специального случая. Когда вы добавляете [this] в список захвата, вы «разрешаете» лямбда вызывать все из текущего объекта. Он также позволяет использовать функции-члены, не используя при этом this->.

Таким образом, ваш вызов do_write(...) можно рассматривать как this->do_write(...)

self только общий указатель, так что будет рассматриваться как любой другой захваченного объекта. Вы должны явно позвонить self->..., чтобы сделать что-нибудь на нем. Я предполагаю, что это необходимо в init-capture, поэтому объект будет сохранен до тех пор, пока идет поток. Просто использование в init-capture не увеличивает счетчик ссылок, поэтому вы можете случайно удалить объект при вызове do_write без него.

+0

Понимание того, что термин 'this' самой лямбда не может быть доступен в' operator() 'также помогает. И что он может иметь захват с именем 'this'. И что он будет неявно использовать * that * 'this' с членами и функциями-членами. – Yakk

+0

Спасибо Hayt и Yakk, это на самом деле делает его намного яснее –

Смежные вопросы