I'm having an issue with a child object needing its parent to destroy it. I want something like the following, it's just an example:
#include <iostream>
#include <vector>
struct Object
{
Object(Object* parent) : parent(parent) {}
Object* parent;
std::vector<Object*> children;
bool flag = false;
void update() { if (flag) parent->deleteChild(this); } // Or mark it for deletion afterwards
void deleteChild(Object* child) { delete child; /*children.erase(/* I need the iterator here);*/ }
};
int main()
{
Object* parent = new Object(nullptr);
for (int i = 0; i < 100; ++i) parent->children.push_back(new Object(parent));
parent->children[42]->flag = true;
for (auto i : parent->children) i->update();
return 0;
}
If I keep track of the child's position in the vector I know how to do it, but I basically want to know how I can erase an element of a vector if I have a pointer to it.
Edit: AndyG was right all along, I can't do what I'm wanting because my Objects are all over the place in memory when I "new" it. I did manage to do it another way using placement new, creating the objects all in one contiguous buffer, but it's definitely not worth the trouble. I did learn a lot though.
#include <iostream>
#include <vector>
struct Object
{
Object(Object* parent, int position) : parent(parent), numberPosition(position)
{
std::cout << "Constructing object number: " << numberPosition << " at at heap memory location: " << this << '\n';
}
Object* parent;
int numberPosition = 0;
std::vector<Object*> children;
bool flag = false;
void update()
{
if (flag) parent->deleteChild(this);
}
void deleteChild(Object* child)
{
Object* pChild = &(*child);
ptrdiff_t position = child - *children.data();
std::vector<Object*>::iterator it = children.begin() + position;
std::cout << "About to delete vector element at position: " << (*it)->numberPosition << '\n';
// delete pChild; Not supposed to deallocate each placement new. See http://www.stroustrup.com/bs_faq2.html#placement-delete and https://stackoverflow.com/questions/222557/what-uses-are-there-for-placement-new
std::cout << "Size of children vector = " << children.size() << '\n';
children.erase(it);
std::cout << "Size of children vector = " << children.size() << '\n';
}
~Object() { std::cout << "Destroying object number " << numberPosition << '\n'; }
};
int main()
{
Object* parent = new Object(nullptr, 0);
char* contiguousBuffer = static_cast<char*>(malloc(100 * sizeof(Object)));
for (int i = 0; i < 100; ++i)
{
Object* newAddress = new (contiguousBuffer + i * sizeof(Object)) Object(parent, i); // Placement new
parent->children.push_back(newAddress);
}
parent->children[42]->flag = true;
//for (auto i : parent->children) i->update(); // Iterator gets invalidated after erasing the element at 42 doing it this way
for (int i = 0; i < parent->children.size(); ++i) parent->children[i]->update();
free(contiguousBuffer);
// Destructors also need to be called
return 0;
}
Unfortunately the only way to do it is to search through the vector like normal.
auto it = std::find(std::begin(children), std::end(children), child);
if (it != std::end(children)){
children.erase(it);
delete child;
}