Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
396 views
in Technique[技术] by (71.8m points)

c++ - Why can't I move the std::unique_ptr inside lambda in C++14?

I want to pass a raw pointer inside lambda, but I don't want it to be leaked, if the lambda isn't invoked. It looks like this:

void Clean(std::unique_ptr<int>&& list);

void f(int* list) {
  thread_pool.Push([list = std::unique_ptr<int>(list) ] {
    Clean(std::move(list));  // <-- here is an error.
  });
}

I get an error in Clang 3.7.0:

error: binding of reference to type 'unique_ptr<[2 * ...]>' to a value of type 'unique_ptr<[2 * ...]>' drops qualifiers

But I don't see any qualifiers at the first place, especially dropped.

Also, I found similar report on the mailing list, but without answer.


How should I modify my code, so it gets compiled and works as expected by semantics?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You need to make the inner lambda mutable:

[this](Pointer* list) {
  thread_pool.Push([this, list = std::unique_ptr<int>(list) ]() mutable {
                                                               ^^^^^^^^^
    Clean(std::move(list));
  });
};

operator() on lambdas is const by default, so you cannot modify its members in that call. As such, the internal list behaves as if it were a const std::unique_ptr<int>. When you do the move cast, it gets converted to a const std::unique_ptr<int>&&. That's why you're getting the compile error about dropping qualifiers: you're trying to convert a const rvalue reference to a non-const rvalue reference. The error may not be as helpful as it could be, but it all boils down to: you can't move a const unique_ptr.

mutable fixes that - operator() is no longer const, so that issue no longer applies.

Note: if your Clean() took a unique_ptr<int> instead of a unique_ptr<int>&&, which makes more sense (as it's a more explicit, deterministic sink), then the error would have been a lot more obvious:

error: call to deleted constructor of `std::unique_ptr<int>`
note: 'unique_ptr' has been explicitly marked deleted here  

    unique_ptr(const unique_ptr&) = delete
    ^

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...