47

I have a vector (order is important) of objects (lets call them myobj class) where I'm trying to delete multiple objects at a time.

class vectorList
{

    vector<*myobj> myList; 
};

class myobj
{

    char* myName;
    int index;
    bool m_bMarkedDelete;
}

I was thinking that the best way to do this would be to mark specific myobj objects for deletion and then call myList.remove_if() on the vector. However, I'm not exactly sure how to use predicates and such for this. Should I create a member variable in the object which allows me to say that I want to delete the myobj and then create a predicate which checks to see if the member variable was set?

How do I implement the predicate as a part of the vectorList class?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Jordan
  • 9,014
  • 8
  • 37
  • 47
  • 1
    It may not be relevant but a std::list retains order and has its own remove_if function which is much faster and does not need the separate erase. – Ant Mar 14 '13 at 13:57
  • 1
    @Ant: `list::remove_if` faster than remove and erase on a vector? Under what circumstances? That certainly hasn't been the case on many reasonable tests that I've ever done. Don't assume that just because erasing is a constant time operation for list, that it will be faster. The contiguity and random access guarantees of `std::vector` buy it an awful lot of performance. – Benjamin Lindley Oct 01 '13 at 23:23

2 Answers2

66

Should I create a member variable in the object which allows me to say that I want to delete the myobj and then create a predicate which checks to see if the member variable was set?

Haven't you already done that? Isn't that what m_bMarkedDelete is for? You would write the predicate like this:

bool IsMarkedToDelete(const myobj & o)
{
    return o.m_bMarkedDelete;
}

Then:

myList.erase(
    std::remove_if(myList.begin(), myList.end(), IsMarkedToDelete),
    myList.end());

Or, using lambdas:

myList.erase(
    std::remove_if(myList.begin(), myList.end(),
        [](const myobj & o) { return o.m_bMarkedDelete; }),
    myList.end());

If your class doesn't actually have that member, and you're asking us if it should, then I would say no. What criteria did you use to decide to mark it for deletion? Use that same criteria in your predicate, for example:

bool IndexGreaterThanTen(const myobj & o)
{
    return o.index > 10;
}

note -- The functions I've written are of course invalid since all your members are private. So you'll need some way to access them.

Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
  • I get the following error because it's a pointer: error C2662: 'myobj::IsMarkedToDelete' : cannot convert 'this' pointer from 'const myobj' to 'myobj &. I'm marking it for deletion since I'm doing it from a class which has a grid which is synchronized with my vector. I have to remove the rows in the grid and then remove the corresponding selected rows in the vector. – Jordan Oct 31 '11 at 19:14
  • @Jordan: It should not be a member, it should be a free function. – Benjamin Lindley Oct 31 '11 at 19:15
  • the IsMarkedToDelete should be a free function? It seems that the problem is with the "const-ness" of the object though... – Jordan Oct 31 '11 at 19:18
  • @Jordan: It's talking about the `this` pointer. There should not be a `this` pointer, because this function should not be a member. – Benjamin Lindley Oct 31 '11 at 19:20
  • Yep, I still get the same error though. cannot convert 'this' pointer from 'const myobj' to 'myobj &' Conversion loses qualifiers. Does this work with vectors of pointers too? – Jordan Oct 31 '11 at 19:23
  • @Jordan: Did you make a public accessor for `m_bMarkedDelete` and not make it const? – Benjamin Lindley Oct 31 '11 at 19:25
  • I'm actually using an integer member/accessor instead of a boolean now, but I've tried making it both const and non-const. The accessor is public. bool IsMarkedToDelete (const myobj& value) {return (value.GetPredicate() == 1); } – Jordan Oct 31 '11 at 19:28
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/4621/discussion-between-jordan-and-benjamin-lindley) – Jordan Oct 31 '11 at 19:30
  • 2
    IsMarkedToDelete should be static function – Erdemus Aug 08 '13 at 14:01
16

A predicate is basically a conditional comparison. It can be a function or object. Here's an example using new C++ lambdas. This code will go through the vector and remove the values equal to 3.

int arg[6] = {1, 2, 3, 3, 3, 5};
std::vector<int> vec(arg, arg+6);
vec.erase(
   std::remove_if(
      vec.begin(), vec.end(),
      [](int i){ return i == 3;}),
   vec.end());

Edit: For pointers let's say you had a vector or interfaces you could set them to nullptr then remove them in a batch with pretty much the same code. In VS2008 you won't have lambdas so make a comparison predicate function or struct instead.

bool ShouldDelete(IAbstractBase* i)
{
    return i == nullptr;
    // you can put whatever you want here like:
    // return i->m_bMarkedDelete;
}

std::vector<IAbstractBase*> vec;
vec.erase(
   std::remove_if(
      vec.begin(), vec.end(),
      ShouldDelete),
   vec.end());
AJG85
  • 15,849
  • 13
  • 42
  • 50
  • How would I do that if the vector is a list of myobj* pointers? That's one of the things that I'm confused about. And will this work in VS 2008? Thanks! – Jordan Oct 31 '11 at 19:08