简体   繁体   中英

How to use std::find_if with a vector of unique pointers?

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 .

  1. 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 ).

  2. [&](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) {... }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM