I wanted to capture std::unique_ptr
into lambda and then move it into another function inside lambda, but my two minimal examples fail to compile and I'm not sure why.
Can somebody explain to me, why it tries to make a copy even though I'm trying to move it in in first example and where does const
qualifier comes from in second example?
First example (function accepts std::unique_ptr by value):
#include <memory>
void sink(std::unique_ptr<int> p) {
// Do something with `p`
}
int main() {
auto p = std::make_unique<int>(42);
auto f = [p = std::move(p)](){
sink(std::move(p));
};
f();
return 0;
}
The error is:
<source>:10:13: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]'
10 | sink(std::move(p));
| ~~~~^~~~~~~~~~~~~~
In file included from /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/memory:78,
from <source>:1:
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/unique_ptr.h:516:7: note: declared here
516 | unique_ptr(const unique_ptr&) = delete;
| ^~~~~~~~~~
<source>:10:13: note: use '-fdiagnostics-all-candidates' to display considered candidates
10 | sink(std::move(p));
| ~~~~^~~~~~~~~~~~~~
<source>:3:32: note: initializing argument 1 of 'void sink(std::unique_ptr<int>)'
3 | void sink(std::unique_ptr<int> p) {
| ~~~~~~~~~~~~~~~~~~~~~^
Compiler returned: 1
Second example (function accepts std::unique_ptr by rvalue ref):
#include <memory>
void sink(std::unique_ptr<int> &&p) {
// Do something with `p`
}
int main() {
auto p = std::make_unique<int>(42);
auto f = [p = std::move(p)](){
sink(std::move(p));
};
f();
return 0;
}
The error is:
<source>: In lambda function:
<source>:10:23: error: binding reference of type 'std::unique_ptr<int>&&' to 'std::remove_reference<const std::unique_ptr<int>&>::type' {aka 'const std::unique_ptr<int>'} discards qualifiers
10 | sink(std::move(p));
| ~~~~~~~~~^~~
<source>:3:34: note: initializing argument 1 of 'void sink(std::unique_ptr<int>&&)'
3 | void sink(std::unique_ptr<int> &&p) {
| ~~~~~~~~~~~~~~~~~~~~~~~^
Compiler returned: 1
Lambda members, the captures, are treated as const
in the lambda body since the synthsized operatror()
is const
. One way to get around that is to make the lambda mutable like
#include <memory>
void sink(std::unique_ptr<int> p) {
// Do something with `p`
}
int main() {
auto p = std::make_unique<int>(42);
auto f = [p = std::move(p)]() mutable {
sink(std::move(p));
};
f();
return 0;
}
and then it will compile.