Search code examples
c++shared-ptrruntimeexception

Why does calling a method on a shared_ptr in a vector throw a runtime exception?


Why does the following code throw

Exception thrown at 0x53A5C6DC (nvoglv32.dll) in RenderEngine.exe: 0xC0000005: Access violation reading location 0x0002B174.

at runtime and what would be a good solution?

std::vector<std::shared_ptr<Static>> statics;

void drawStatics() {
    for (std::shared_ptr<Static> stat: statics) {
        Static *statptr = stat.get();

        statptr->Draw(); //This is what triggers the runtime exception.
    }
}

void addStatic(Mesh &mesh, Texture &texture, Transform transform) {
    statics.push_back(
        std::make_shared<Static>(
            mesh,
            texture,
            transform,
            shader,
            camera
        ));
}

int main() {
    addStatic(playerMesh, playerTexture, platformTransform);
    drawStatics();

    return 0;
}

The Static header file is as follows:

#pragma once

#include "mesh.h"
#include "texture.h"
#include "transform.h"
#include "camera.h"
#include "shader.h"

class Static {
public:
    Static(Mesh &mesh, Texture &texture, Transform &transform, Shader &shader, Camera &camera);
    ~Static();

    void Draw();

private:
    Mesh *mesh;
    Texture *texture;
    Transform *transform;
    Shader *shader;
    Camera *camera;
};

In the Static source file Draw() is implemented as:

void Static::Draw() {
    texture->Bind(0);
    shader->Update(*transform, *camera);
    mesh->Draw();
}

And the Static constructor and deconstructor as requested:

Static::Static(Mesh &mesh, Texture &texture, Transform &transform, Shader &shader, Camera &camera)
    :mesh(&mesh), texture(&texture), transform(&transform), shader(&shader), camera(&camera)
{}

Static::~Static() {}

EDIT: I am using visual studio if that matters.


Solution

  • That's what you get from throwing pointers and references all over your code and not thinking about lifetimes.

    void addStatic(Mesh &mesh, Texture &texture, Transform transform) {
    

    You take a Transform by value, which means, it gets copied, so the function has it's own instance.

     std::make_shared<Static>(
                mesh,
                texture,
                transform,
                shader,
                camera
            ));
    
    Static::Static(Mesh &mesh, Texture &texture, Transform &transform, Shader &shader, Camera &camera)
        :mesh(&mesh), texture(&texture), transform(&transform), shader(&shader), camera(&camera)
    {}
    

    You pass a reference to the local variable to Static::Static, take the pointer of it and store the pointer. addStatic returns, the local Transform gets destroyed and you end up with a dangling pointer to a free'd chunk of memory in your Transform*.

    Not sure about your other pointers, but you take everything as reference, so please check, when they are going to be destroyed, the other pointers might point to free'd space aswell.


    By the way:

    Static *statptr = stat.get();
    statptr->Draw();
    

    You don't need to get() the pointer. C++'s smart pointers behave (almost) like the raw pointers, so

    stat->Draw();
    

    works.