-1

I'm pretty new to C++ so I hope I can get some help here. I try to port my Game Engine to C++ but C++ behaves a litle bit... "Strange". Following Situation:

if I run test1() It all works as it should.

main.cpp

#include <iostream>

#include "../headers/base.h"

#include "../headers/DemoGame.h"
#include "../headers/TestShader.h"

using namespace std;
using namespace engine;


void run(TestShader* t, GLuint VAO, GLFWwindow* w)
{
    glfwPollEvents();


    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(t->progID);
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glBindVertexArray(0);

    glfwSwapBuffers(w);
}

void test1()
{
    Window w = Window(800, 600, "test");
    TestShader t = TestShader();
    GLuint VAO, VBO;

    GLfloat vertices[9] = {
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
        0.0f,  0.5f, 0.0f
    };


    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindVertexArray(0);

    while (!glfwWindowShouldClose(w.getWindow()))
    {
        run(&t, VAO, w.getWindow());
    }


}

void test2()
{
    DemoGame game = DemoGame();
    game.start();
}

int main()
{

    test1();

    return 0;
}

If i'm running test2() with following involved classes:

Engine.h

#pragma once

#ifndef H_ENGINE
#define H_ENGINE

#include "base.h"

namespace engine
{
    class Engine
    {
        private:
            bool running;

        public:
            void start()
            {
                init();
                process();
            }

            void stop()
            {
                this->running = false;
            }

        private:
            void process()
            {
                update();
            }

        public:
            virtual void init() = 0;
            virtual void update() = 0;
            virtual void render() = 0;
            virtual void terminate() = 0;
    };
}

#endif

DemoGame.h

#pragma once

#ifndef DEMO_DEMO_GAME
#define DEMO_DEMO_GAME

#include "base.h"

#include "Window.h"
#include "Engine.h"
#include "TestShader.h"


using namespace engine;

class DemoGame : public Engine
{

    public:
        Window* w;
        TestShader* t;

        GLuint VBO, VAO;

    public:
        DemoGame() : Engine() { }

    public:
        void init();

        void update();

        void render();

        void terminate();
};

#endif

DemoGame.cpp

#include "../headers/DemoGame.h"
#include <iostream>

using namespace std;

void DemoGame::init()
{
    cout << "ping" << endl;

    Window wi = Window(800, 600, "test");
    w = &wi;
    TestShader te = TestShader();
    t = &te;



    GLfloat vertices[9] = {
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
        0.0f,  0.5f, 0.0f
    };


    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindVertexArray(0);

    while (!glfwWindowShouldClose(w->getWindow()))
    {
        render();
    }
}

void DemoGame::update()
{

}

void DemoGame::render()
{
    glfwPollEvents();


    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(t->progID);
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glBindVertexArray(0);

    glfwSwapBuffers(w->getWindow());
}

void DemoGame::terminate()
{

}

It works aswell. But as you may see Engine.h is supposed to control the mainloop. If I change the code a little bit:

Engine.h

#pragma once

#ifndef H_ENGINE
#define H_ENGINE

#include "base.h"

namespace engine
{
    class Engine
    {
        private:
            bool running;

        public:
            void start()
            {
                init();

                running = true;

                while (running)
                {
                    process();
                }

            }

            void stop()
            {
                this->running = false;
            }

        private:
            void process()
            {
                update();
            }

        public:
            virtual void init() = 0;
            virtual void update() = 0;
            virtual void render() = 0;
            virtual void terminate() = 0;
    };
}

#endif

DemoGame.cpp

#include "../headers/DemoGame.h"
#include <iostream>

using namespace std;

void DemoGame::init()
{
    cout << "ping" << endl;

    Window wi = Window(800, 600, "test");
    w = &wi;
    TestShader te = TestShader();
    t = &te;



    GLfloat vertices[9] = {
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
        0.0f,  0.5f, 0.0f
    };


    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindVertexArray(0);

}

void DemoGame::update()
{
    render();
}

void DemoGame::render()
{
    glfwPollEvents();


    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(t->progID);
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glBindVertexArray(0);

    glfwSwapBuffers(w->getWindow());
}

void DemoGame::terminate()
{

}

Now all of a sudden I get an "Access Violation". The question is why? The file "base.h" just contains

#define GLEW_STATIC
#include "GL/glew.h"
#include "GLFW/glfw3.h"

and the classes Window and TestShader shouldn't matter because they work in the first two examples. As I stated before I'm pretty new to C++ and I just don't understand why that doesn't work. Can you please help me finding out at least why that doesn't work or better help me solving the problem.

This is my second attempt to get a useful answer from StackOverflow by posting a question. Please do me a favour. Please consider read the situation before you mark this question an duplicate. The last time it wasn't an duplicate the problem was by far different.

Edit

As requested the Error message(sry I'm at work so the language is german)

Ausnahme ausgelöst bei 0x0126489D in GLFWGame.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0xCCCCCEA4.

Falls ein Handler für diese Ausnahme vorhanden ist, kann das Programm möglicherweise weiterhin sicher ausgeführt werden.

And I'll try to shorten the code to the most important.

picatrix
  • 11
  • 4
  • 3
    The right tool to solve such problems is your debugger. You should step through your code line-by-line *before* asking on Stack Overflow. For more help, please read [How to debug small programs (by Eric Lippert)](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). At a minimum, you should \[edit] your question to include a [Minimal, Complete, and Verifiable](http://stackoverflow.com/help/mcve) example that reproduces your problem, along with the observations you made in the debugger. – πάντα ῥεῖ Dec 28 '16 at 15:53
  • Can you post the actual error message? – AresCaelum Dec 28 '16 at 15:55
  • 1
    from what I can see I'm surprised you didnt get the "Access Violation" in your first test case. You are setting pointers to point at variables that go out of scope at the end of your DemoGame::Init() function. Which means they get cleaned up and causes undefined behaviour. – AresCaelum Dec 28 '16 at 16:04

2 Answers2

1

You store addresses of stack objects that get deleted. For example,

Window wi = Window(800, 600, "test");
w = &wi;

Creates a local variable wi on the stack, which gets deleted automatically when it goes out of scope (which is the case at the end of the function). After that, w will point to an address that is already freed, which will lead to big troubles when you try to access this variables later on as you do here:

glfwSwapBuffers(w->getWindow());

If you want to create the window object on the heap, you have to use the following code in DemoGame::init():

w = new Window(800, 600, "test");

Don't forget to delete this object manually by calling delete w when you don't need it anymore. The same problem also occures for the TestShader instance.

Side note: Window wi = Window(800, 600, "test"); is still a strange syntax when creating objects on the stack. The correct way would be Window wi(800, 600, "test"); Have a look at this posts for why this makes a difference: Calling constructors in c++ without new

Edit: Your first example just works because you are calling the render function inside the init function, thus the objects do not get out of scope. Storing pointers to local object is still not good practice.

Community
  • 1
  • 1
BDL
  • 18,169
  • 14
  • 45
  • 47
1

Your problem is here:

Window wi = Window(800, 600, "test");
w = &wi;
TestShader te = TestShader();
t = &te;

Both, the instance of Window as well as the instance of TestShader are local variables that will get cleaned up as soon as they go out of scope (end of init) and hence remembering their addresses has no meaning. You will need to create those instances dynamically (new) or set them up within your class definition.

BDL
  • 18,169
  • 14
  • 45
  • 47
Till
  • 27,364
  • 13
  • 84
  • 120