OpenGL的C ++奇怪的访问冲突[关闭]

Posted

技术标签:

【中文标题】OpenGL的C ++奇怪的访问冲突[关闭]【英文标题】:C++ Strange Access Violation with OpenGL [closed] 【发布时间】:2016-12-28 15:51:25 【问题描述】:

我对 C++ 还很陌生,所以我希望在这里能得到一些帮助。 我尝试将我的游戏引擎移植到 C++,但 C++ 的行为有点……“奇怪”。 以下情况:

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

ma​​in.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;

如果我使用以下涉及的类运行 test2():

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++ 很陌生,我只是不明白为什么这不起作用。你能帮我找出至少为什么这不起作用或更好地帮助我解决问题吗?

这是我第二次尝试通过发布问题从 *** 获得有用的答案。请帮我一个忙。在将此问题标记为重复之前,请考虑阅读情况。上次它不是重复时,问题就大不相同了。

编辑

根据要求提供错误消息(对不起,我在工作,所以语言是德语)

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

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

我会尽量缩短代码到最重要的部分。

【问题讨论】:

调试器是解决此类问题的正确工具。 询问 Stack Overflow 之前,您应该逐行浏览您的代码。如需更多帮助,请阅读How to debug small programs (by Eric Lippert)。至少,您应该 [编辑] 您的问题以包含一个重现您的问题的 Minimal, Complete, and Verifiable 示例,以及您在调试器中所做的观察。 你能贴出实际的错误信息吗? 据我所知,我很惊讶您在第一个测试用例中没有遇到“访问冲突”。您正在将指针设置为指向在 DemoGame::Init() 函数末尾超出范围的变量。这意味着它们会被清理并导致未定义的行为。 【参考方案1】:

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

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

在堆栈上创建一个局部变量wi,当它超出范围时会自动删除(函数结束时就是这种情况)。之后,w 将指向一个已经被释放的地址,当您稍后尝试访问此变量时,这将导致很大的麻烦,就像您在这里所做的那样:

glfwSwapBuffers(w->getWindow());

如果要在堆上创建window对象,必须在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 函数中调用了渲染函数,因此对象不会超出范围。存储指向本地对象的指针仍然不是一个好习惯。

【讨论】:

还应该提到,如果他正在调用new,他需要使用delete,或者他可以使用shared_ptr 有效!谢谢你!这将是我走过的最艰难的学习之路......【参考方案2】:

你的问题在这里:

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

Window 的实例和TestShader 的实例都是局部变量,一旦它们超出范围(初始化结束)就会被清理,因此记住它们的地址没有任何意义。您将需要动态创建这些实例 (new) 或在您的类定义中设置它们。

【讨论】:

以上是关于OpenGL的C ++奇怪的访问冲突[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

双重比较的C ++非常奇怪的行为[关闭]

如何在没有有用的调用堆栈的情况下调试难以重现的崩溃?

OpenGL 和 GLUT/C++ 奇怪的纹理循环问题

从 DllImport 启动的 C++ 方法的访问冲突

检测超出数组访问冲突

glew未定义的OpenGL函数[关闭]