This is a simplified version of my program.
#include <iostream>
#include <vector>
class Base
{
public:
Base()
{
}
void virtual update()
{
std::cout << "no update function\n";
}
void virtual draw()
{
std::cout << "no draw function\n";
}
};
class Derived : public Base
{
public:
Derived();
void draw() override;
void update() override;
};
Derived::Derived()
{
}
void Derived::draw()
{
std::cout << "draw";
}
void Derived::update()
{
std::cout << "update";
}
class Caller
{
public:
Caller();
void update();
void draw();
void reg_obj(Base* obj);
private:
std::vector<std::shared_ptr<Base>> all_objects;
};
Caller::Caller()
{
Derived derived_class{};
reg_obj(&derived_class);
}
void Caller::update()
{
for (int i = 0; i < all_objects.size(); i++)
{
all_objects[i]->update();
}
}
void Caller::draw()
{
for (int i = 0; i < all_objects.size(); i++)
{
all_objects[i]->draw();
}
}
void Caller::reg_obj(Base* obj)
{
all_objects.push_back(std::shared_ptr<Base>{obj});
}
int main()
{
Caller caller{};
while (true)
{
caller.update();
caller.draw();
}
}
This code works, but when it's in my full program between caller.update();
and caller.draw();
the __vfptr value in memory does not stay the same. When approaching caller.draw()
the __vfptr value changes every step through the debugger. I'm not sure how to diagnose memory corruption in __vfptr as it's not something I programmed, but part of the C++ standard. Any help is appreciated. And no, I can't make a reproducible version. I don't know why. I did make an effort to make it reproducible.
https://youtu.be/yd-76qDa7xc <- this video shows the problem https://github.com/Sage-King/Alienor <- source for non-functional code
Solution from Remy Lebeau:
Derived derived_class{}; reg_obj(&derived_class);
is causing undefined behavior in the rest of your code. You are storing a pointer to a local object that is destroyed afterwards, leaving a dangling pointer in the all_objects
vector. All of your method calls on all_objects
elements are acting on invalid memory. To fix that, change void reg_obj()
to take a shared_ptr<Base>
and store it as-is, and then change Caller()
to create the Derived
object using std::make_shared()
like this: void Caller::reg_obj(std::shared_ptr<Base> obj) { all_objects.push_back(obj); } Caller::Caller() { reg_obj(std::make_shared<Derived>()); }