-4

I have a vector foos of unique pointers to my resource type Foo. I would like to delete some of these that satisfy a given condition. How should I do this ?

class Foo
{
public:
    int some_num;
    Foo(int some_num_) :some_num{ some_num_ }
    {}
    int getNum()
    {
        return some_num;
    }
};

using FooPtr = std::unique_ptr<Foo>;
using Foos = std::vector<FooPtr>;

int main()
{
    Foos foos;
    foos.push_back(std::move(std::make_unique<Foo>(30)));
    foos.push_back(std::move(std::make_unique<Foo>(35)));
    std::vector<int> some_nums = { 35, 30, 25 };
    for each (auto& num in some_nums)
    {
        foos.erase(std::remove_if(foos.begin(), foos.end(), 
             [&](auto foo) {return num == foo->getNum(); }), foos.end());
    }
    return 0;
}

It looks like I'm copying the unique_ptr and so I get the following error,

'std::unique_ptr<Foo,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function

How should I do this ? I will not be using the resource. I don't care about the ownership beyond this point.

rranjik
  • 690
  • 9
  • 21
  • s/`for each (auto& num in some_nums)`/`for(auto& num : some_nums)` – user0042 Nov 20 '17 at 17:24
  • 1
    Why are you passing the return value of `std::remove_if` to `std::vector::erase`? According to the [documentation](http://en.cppreference.com/w/cpp/algorithm/remove) the return value is "_Past-the-end iterator for the new range of values_" Did you really mean to erase the element pointed at by such iterator, **in addition to** the values that satisfied the lambda? – Algirdas Preidžius Nov 20 '17 at 17:27
  • @AlgirdasPreidžius I suppose this is called the erase-remove idiom. Also from the manual [here](http://en.cppreference.com/w/cpp/container/vector/erase) and [here](http://en.cppreference.com/w/cpp/algorithm/remove): "A call to remove is typically followed by a call to a container's erase method, which erases the unspecified values"..., "Iterators pointing to an element between the new logical end and the physical end of the range are still dereferenceable, but the elements themselves have unspecified values", "The iterator pos must be valid and dereferenceable." – rranjik Nov 21 '17 at 04:15
  • @user3222 What in the copied snippet states, that **you** should call `erase` on your own? You just copied a description of what said procedure does. – Algirdas Preidžius Nov 21 '17 at 13:05
  • @AlgirdasPreidžius I did mention that "I would like to delete some of these that satisfy a given condition." So, I should get rid of these elements from my container shouldn't I ? – rranjik Nov 21 '17 at 13:11
  • @AlgirdasPreidžius std::remove_if does not delete the elements by itself, it just moves the elements that satisfy the predicate, to the end of the vector, moving the rest to the front. After doing so it points to the end (off by one) of the new range. Where is it mentioned that vector's erase removes one additional element ? I'm using the second overload of erase that will delete [first, last), in my case all elements that satisfied the condition. Where am I deleting unnecessary elements ? – rranjik Nov 21 '17 at 15:06

1 Answers1

4

The auto deduction rules will deduce the type to be std::unique_ptr, forcing a copy. So just change the parameter type of the lambda expression to

[&](const auto& foo) {return num == foo->getNum(); })
Jodocus
  • 7,493
  • 1
  • 29
  • 45