使用OpenGL进行C ++奇怪的访问冲突

时间:2016-12-28 15:51:26

标签: c++ opengl glfw glew

我对C ++很陌生,所以我希望我能在这里得到一些帮助。 我尝试将我的游戏引擎移植到C ++,但C ++表现得很轻微......“奇怪”。 以下情况:

如果我运行test1()它一切正常。

的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;
}

如果我正在运行带有以下相关类的t​​est2():

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()
{

}

它也有效。但正如您可能会看到Engine.h应该控制主循环。如果我稍微改变一下代码:

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()
{

}

现在突然间我得到了“访问冲突”。问题是为什么? 文件“base.h”只包含

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

并且Window和TestShader类应该无关紧要,因为它们适用于前两个示例。正如我之前所说,我对C ++很陌生,我只是不明白为什么这不起作用。能否请你帮我找出至少为什么不起作用或更好地帮我解决问题。

这是我第二次尝试通过发布问题从StackOverflow获得有用的答案。请帮个忙。在将此问题标记为重复之前,请考虑阅读此情况。最后一次不是重复,问题远远不同。

修改

根据要求提供错误消息(我正在工作,因此语言为德语)

  

GLFWGame.exe中的Ausnahmeausgelöstbei0x0126489D:0xC0000005:   Zugriffsverletzung beim Lesen职位0xCCCCCEA4。

     

Falls einHandlerfürdieseAusnahme vorhanden ist,kann das Programm   möglicherweiseweiterhinsicherausgeführtwerden。

我会尝试将代码缩短到最重要的位置。

2 个答案:

答案 0 :(得分:1)

存储被删除的堆栈对象的地址。例如,

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

在堆栈上创建一个局部变量wi,当它超出范围时会自动删除(在函数末尾就是这种情况)。在那之后,w将指向一个已经被释放的地址,这将在您稍后尝试访问此变量时导致严重问题:

glfwSwapBuffers(w->getWindow());

如果要在堆上创建窗口对象,则必须在DemoGame::init()中使用以下代码:

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

请勿忘记在您不再需要时通过致电delete w手动删除此对象。 TestShader实例也会出现同样的问题。

旁注: Window wi = Window(800, 600, "test");在堆栈上创建对象时仍然是一种奇怪的语法。正确的方法是Window wi(800, 600, "test");看看这些帖子,了解为什么会产生影响:Calling constructors in c++ without new

编辑:你的第一个例子正常工作,因为你在init函数中调用了render函数,因此对象不会超出范围。存储指向本地对象的指针仍然不是很好的做法。

答案 1 :(得分:1)

你的问题在这里:

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

两者,Window的实例以及TestShader的实例都是局部变量,一旦它们超出范围(init结束)就会被清除,从而记住它们的地址没有任何意义。您需要动态创建这些实例(new)或在类定义中进行设置。