Search code examples
c++inheritancepolymorphismvirtual-functions

Read Access Violation on Virtual Function


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

  • 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>()); }