-1

I am currently facing issues while writing/utilizing a destructor for my Model class. For an OpenGL assignment I have to write a data structure which holds all the information regarding a model, see my Model.h implementation below. This class contains pointers to a variety of structs, and I have learned to properly clean up after allocating memory on the heap.

Currently, my application is working fine while having my destructor commented out, this does gives me memory leaks though and I am pretty sure my lecturer will give me a significant lower grade because of this.

However, when defining (uncommenting) my destructor, I encounter problems. After running a method called InitModels (see implementation below), my destructor gets called which throws an application breaking exception:

Exception thrown during destructor

What am I missing here? I have heard and read some stuff about the rule of three which might be related to my problem, but I am stuck where to start applying this rule in my case.

This is my InitModels method:

void InitModels()
{
    /*
        Teapot model
    */
    Model teapot("Teapot");
    teapot.material = new Material(glm::vec3(0.0, 0.0, 0.0),
                                    glm::vec3(0.0, 0.0, 0.0),
                                    glm::vec3(1.0), 128);
    teapot.mesh = new Mesh("Objects/teapot.obj");
    teapot.modelMatrix = new ModelMatrix(glm::mat4());
    teapot.texture = new Texture("Textures/Yellobrk.bmp", true, loadBMP("Textures/Yellobrk.bmp"));
    teapot.transformations = new Transformations(true, 0.01f, glm::vec3(0.0f, 1.0f, 0.0f));
    models.push_back(teapot);
}

Here is my Model.h:

#include <iostream>
#include <vector>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "glsl.h"
#include "objloader.hpp"

#pragma once


struct Material
{
    glm::vec3 ambientColor;
    glm::vec3 diffuseColor;
    glm::vec3 specular;
    float power;
    /*
        Initializer list constructor
    */
    Material(){ }
    Material(glm::vec3 ambient, glm::vec3 diffuse, glm::vec3 spec, float pwr) :
        ambientColor(ambient), diffuseColor(diffuse), specular(spec), power(pwr) { }
};

struct Mesh
{
    char* fileLocation; // location of object file
    vector<glm::vec3> vertices;
    vector<glm::vec3> normals;
    vector<glm::vec2> uvs;

    /*
        Initializer list constructor
    */
    Mesh(char* fileLoc) : fileLocation(fileLoc) { }
    Mesh(char* fileLoc, vector<glm::vec3> vert, vector<glm::vec3> normals, vector<glm::vec2> uvs) :
        fileLocation(fileLoc), vertices(vert), normals(normals), uvs(uvs) { }
    ~Mesh() { }
};

struct ModelMatrix
{
    glm::mat4 model;
    glm::mat4 mv;

    /*
        Initializer list constructor
    */
    ModelMatrix() { }
    ModelMatrix(glm::mat4 model) : model(model) { }
    ModelMatrix(glm::mat4 model, glm::mat4 mv) : model(model), mv(mv) { }
};

struct Texture
{
    char* fileLocation; // location of texture file
    bool applyTexture;
    GLuint textureID;

    /*
        Initializer list constructor
    */
    Texture() { }
    /*Texture(char* fileLocation, bool applyTexture) :
        fileLocation(fileLocation), applyTexture(applyTexture) 
    {
        textureID = loadBMP(fileLocation);
    }*/

    Texture(char* fileLocation, bool applyTexture, GLuint textureID) :
        fileLocation(fileLocation), applyTexture(applyTexture), textureID(textureID) { }
    ~Texture() { }
};

struct Transformations
{
    bool rotationEnabled;
    float angle;
    glm::vec3 axis;
    Transformations() { }
    Transformations(bool rotEnabled, float angle, glm::vec3 axis)
        : rotationEnabled(rotEnabled), angle(angle), axis(axis) { }
    ~Transformations() { }
};

class Model {
public:

    Model(string modelName)
    {
        name = modelName;
    }

    ~Model();
    string name;
    GLuint vao;
    Material * material;
    Texture* texture;
    Mesh* mesh;
    ModelMatrix* modelMatrix;
    Transformations* transformations;
};
J. Doe
  • 101
  • 10
  • 2
    It's probably irrelevant that you are using OpenGL in the background, it seems you are stumbling over generic C++ issues. That said, please extract a [mcve]. – Ulrich Eckhardt Apr 08 '18 at 09:51
  • 3
    Here's a hint. In every class that holds a raw pointer, add `class_name(class_name const&) = delete;` and `class_name& operator=(class_name const&) = delete;`. Whenever a compiler error pops up, is where your code is messing up. – StoryTeller - Unslander Monica Apr 08 '18 at 09:57
  • Another hint, which will cover some of the issues that StoryTeller's hint will expose .... google for "rule of three" and (for C++11 and later) "rule of five" – Peter Apr 08 '18 at 10:03

1 Answers1

1

"I have heard and read some stuff about the rule of three which might be related to my problem" you are correct regarding this. https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)

in void InitModels() you create Model on the stack, and then push a copy to the vector models.push_back(teapot);, you didn't define a copy constructor so the compiler create the default one. which just do a simple copy of the pointers. once the code go out of scope the destructor of this item is called. and the pointers become invalid, hance the item in the vector is now having invalid pointers. once the vector destructor is called it calls the destructor of the Model and you doing delete on already deleted pointer.

you can fix this by using unique_ptr and define the copy constructor.

Arkady Godlin
  • 588
  • 2
  • 9