How do you use algorithms like std::find_if
with a vector of unique pointers? For instance:
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
class Integer {
public:
explicit Integer(int i): i_(i){};
int get() const{
return i_;
}
private:
int i_;
};
using IntegerPtr = std::unique_ptr<Integer>;
int main() {
IntegerPtr p1 = std::make_unique<Integer>(4);
IntegerPtr p2 = std::make_unique<Integer>(5);
IntegerPtr p3 = std::make_unique<Integer>(6);
std::vector<IntegerPtr> vectorOfIntegerPointers({
std::move(p1),
std::move(p2),
std::move(p3),
});
int i = 5;
auto first_index_larger_than_i = std::find_if(vectorOfIntegerPointers.begin(), vectorOfIntegerPointers.end(), [&](IntegerPtr s) {
return s->get() > i;
});
std::cout << first_index_larger_than_i.get() << std::endl;
return 0;
}
Fails with
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1881:31: error: call to implicitly-deleted copy constructor of 'std::__1::unique_ptr<Integer, std::__1::default_delete<Integer> >'
::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There are 2 problems in the code both leading to an attempt to copy the non-copyable unique_ptr
.
unique_ptr
can't be passed to vector(initializer_list)
constructor, because initializer_list
wraps its elements as const
objects, and a const
object cannot be moved-from. So the move-constructor doesn't participate in overload resolution, leaving only the copy constructor as a candidate, which later fails to compile with the error you saw: "call to implicitly-deleted copy constructor".
So you have to use another solution to construct vector<unique_ptr>
, for example using push_back
:
std::vector<IntegerPtr> vectorOfIntegerPointers;
vectorOfIntegerPointers.push_back(std::make_unique<Integer>(4));
vectorOfIntegerPointers.push_back(std::make_unique<Integer>(5));
vectorOfIntegerPointers.push_back(std::make_unique<Integer>(6));
Or write a wrapper to hold unique_ptr
as mutable
members (example).
[&](IntegerPtr s) { ... }
used in std::find_if
attempts to take instances of unique_ptr
by-value. But unique_ptr
is not copyable, hence the same error.
A quick fix is to take them by-reference instead:
[&](IntegerPtr const& s) { ... }