Capture unique_ptr in lambda function

Question | Jul 10, 2019 | nextptr 

Overview

There are situations when it is necessary to capture a unique_ptr in a lambda expression. For instance, when a unique_ptr is pointing to a large amount of data that is very expensive to copy and has to be processed by a lambda. Another case in point is, a lambda executing in a separate thread for asynchronous processing needs to capture a unique_ptr. We will consider one of those cases here.

Prior to C++14, it was not possible to capture a unique_ptr in a lambda. The C++14 standard introduced Generalized lambda capture, which makes it possible to capture a unique_ptr in a lambda expression. The Generalized lambda capture is not specific to unique_ptr, it is a general solution. In brief, since C++14 it is possible to define and initialize a new variable in the capture clause of a lambda, e.g.:

std::string str("Hello World");
auto lc = [s = str]() {
 //...
};

//It is also possible to move-construct a variable
auto lm = [s = std::move(str)]() {
 //...
};

This article assumes we are working with C++14 here.

How to capture a unique_ptr?

Assume a struct, Data, can hold a large amount of data:

struct Data {
 // Holds large data
};

The CreateDataProcessor dynamically allocates Data and fills it with a large amount of data, which is very expensive to copy. A lambda expression that can be called to process the data is returned. The returned lambda needs a capture clause (which replaces /*Capture pData*/ below) that can capture the unique_ptr pData appropriately:

auto CreateDataProcessor() {
  // Dynamically allocate Data
  auto pData = std::make_unique<Data>();

  // Fill Data here 

  // Return a lambda that processes data
  return [/*Capture pData*/]( ) { 
    // Process Data in pData
  }; 
}

Select the correct capture clause for above lambda that compiles and runs without any error (check Explanations for details):

2015 nextptr