2

I have got two std::vectors of pointers to classes A and B and am trying to make a method that removes an object from those vectors. This Object may or may not be a subclass of A and/or B and does not have to be an Element of any of the vectors. I have tried following code:

void removeObject(void *object) {
    A *pa = static_cast<A*>(object);
    std::vector<A*>::iterator aPos = std::find(as.begin(), as.end(), pa);
    if (aPos != as.end())
        as.erase(aPos);
    B *pb = static_cast<B*>(object);
    std::vector<B*>::iterator bPos =  std::find(bs.begin(), bs.end(), pb);
    if (bPos != bs.end())
        bs.erase(bPos);
}

but the pointers have different values, so std::find doesn't work (or rather it works sometimes). After reading Multiple inheritance pointer comparison and C++ pointer multi-inheritance fun I understand why, but in both cases the suggested solution was to cast the pointer to *subclass. My questions are:

  1. How can I check whether two pointers refer to the same object without knowing its type?
  2. Is there a more elegant solution to my problem?

I am new to C++ so please excuse me if I have thoroughly misunderstood something...

A. Vosch
  • 23
  • 3
  • I don't believe there's a solution in the language itself. Your solution will probably involve a convention ... e.g., all objects that you're going to want to compare in this way will inherit from an (interface) class that provides a single virtual function that returns void* which is implemented by `return static_cast(this)` and then you compare the pointers you get back from that call. If you're a Windows programmer - it's like how you always compare two COM objects by first doing a QueryInterface for IUnknown and then comparing those two IUnknown pointers. – davidbak May 27 '16 at 17:34
  • Please explain your class hierarchy. It seems that both A and B needs to related via some common base class that would have the Type information in the form of for eg. enum. In that case you can cast void* to that base class and find the underlying type by reading the enum which should have been set while creating the class instance. There might be some other tricky solution, but I am not able to come up with one, especially with multiple inheritence it becomes more tricky – Arunmu May 27 '16 at 17:39

2 Answers2

3

If your classes are polymorphic (have at least one virtual function) then dynamic_cast<void *>() will return a pointer to the beginning of the most-derived object - so it will always return the same answer for the same object even if you start from pointers to unrelated base classes.

But if you have already converted the pointer you had to void * it's too late for that. You might be better off just storing pointers to some common base class.

Alan Stokes
  • 18,815
  • 3
  • 45
  • 64
1

void* is an old C concept in C++ you want to know what type you're working with because that's the foundation of template programming. To that end lets change your function signature to:

template <typename T>
void removeObject(T* object);

From here we can use is_base_of to identify whether the type is a base of the elements of each vector's value_type:

if(is_base_of_v<T, decltype(as)::value_type>) {
    auto aPos = find(cbegin(as), cend(as), *static_cast<A*>(object));

    if(aPos != cend(as)) as.erase(aPos);
}

if(is_base_of_v<T, decltype(bs)::value_type>) {
    auto bPos = find(cbegin(bs), cend(bs), *static_cast<B*>(object));

    if(bPos != cend(bs)) bs.erase(bPos);
}

Obviously, the static_cast would be completely illegal if object was a pointer to an actual base class. I'm assuming that even though though object is a pointer to a base class it's really of the type it's being static_cast to, otherwise we need to go back to the drawing board.

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288