首页 文章

ArticxEngine.exe中0x777122D2(ntdll.dll)的未处理异常:0xC0000005:访问冲突写入位置0x00000004

提问于
浏览
1

我在运行程序时在VS2012中收到此错误 . Visual Studio似乎将问题引向 sf::RenderWindow Articx::window; Articx.cpp

ArticxEngine.exe中0x777122D2(ntdll.dll)的未处理异常:0xC0000005:访问冲突写入位置0x00000004 .

代码 Articx.h

#pragma once

#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>

class Articx
{
    public:
        static void Start();
    private:
        static void GameLoop();

        static bool isExiting();

        enum ScreenState {before, splash1, splash2, splash3, menu, pause, playing, exit};
        static ScreenState currentState;

        static sf::RenderWindow window;
};

代码 Articx.cpp

#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <iostream>
#include <string>
#include "Articx.h"

inline void Message(char message[]);
inline void CallError(int code, char message[]);

Articx::ScreenState Articx::currentState = Articx::before;
sf::RenderWindow Articx::window;

void Articx::Start()
{
    Message("Articx Engine 1.0 Initializing...");

    if(currentState != before)
        return;

    window.create(sf::VideoMode(800,600,32), "Articx Engine 1.0");
    currentState = playing;

    while (!isExiting())
    {
        Message("Engine Initialized");
        Articx::GameLoop();
    }

    window.close();
}

bool Articx::isExiting()
{
    if(currentState == exit)
        return true;
    else
        return false;
}

void Articx::GameLoop()
{
    sf::Event currentEvent;

    while ( window.pollEvent(currentEvent) )
    {
        switch(currentState)
        {
            case Articx::playing:
                {
                    window.clear(sf::Color(0,0,0));
                    window.display();

                    if ( currentEvent.type == sf::Event::Closed )
                        currentState = exit;
                    break;
                }
        }
    }

    window.display();
}

inline void CallError(int code, char message[])
{
    std::cout << "ERROR CODE - " << code << std::endl << message << std::endl << "Will now exit..." << std::endl;
    system("PAUSE");
}

inline void Message(char message[])
{
    std::cout << "AX-MESSAGE: " << message << std::endl;
}

代码 main.cpp

#include "Articx.h"

using namespace std;

int main(int argc, char** argv)
{
    Articx::Start();
    return 0;
}

1 回答

  • 6

    The "Bottom Line" Reason

    未处理异常的原因是因为您将Articx :: window定义为静态变量 .

    The Technical Explanation

    抛出异常是因为构造sf:RenderWindow按此顺序调用以下构造函数:

    RenderWindow :: RenderWindow()Window :: Window()GlResource :: GlResource()

    GlResource :: GlResource()构造函数尝试锁定全局互斥锁:

    namespace
    {
        // OpenGL resources counter and its mutex
        unsigned int count = 0;
        sf::Mutex mutex;
    }
    
    
    namespace sf
    {
    ////////////////////////////////////////////////////////////
    GlResource::GlResource()
    {
        {
            // Protect from concurrent access
            Lock lock(mutex);
    
            // If this is the very first resource, trigger the global context initialization
            if (count == 0)
                priv::GlContext::globalInit();
    
            // Increment the resources counter
            count++;
        }
    
        // Now make sure that there is an active OpenGL context in the current thread
        priv::GlContext::ensureContext();
    }
    

    问题是你的Articx :: window和SFML的sf :: Mutex互斥体都是在程序初始化时构造的全局/静态变量 . 首先构建哪一个?在你的情况下,你的窗口是首先构造的,所以GlResource :: GlResource()构造函数试图锁定一个无效的sf :: Mutex . 由于全局/静态变量的构造顺序可能无法预测,因此最好在非全局位置创建sf :: RenderWindow对象 .

    The Solution

    在main.cpp中,在main()中创建sf :: RenderWindow对象,通过Articx :: Start()传递对窗口的引用:

    #include "Articx.h"
    
    using namespace std;
    
    int main(int argc, char** argv)
    {
        sf::RenderWindow window;
    
        Articx::Start(window);
        return 0;
    }
    

    在Articx.h中,删除静态成员变量窗口,然后展开Start()和Gameloop()以接受sf :: RenderWindow引用:

    #pragma once
    
    #include <SFML/Graphics.hpp>
    #include <SFML/Window.hpp>
    
    class Articx
    {
        public:
            static void Start(sf::RenderWindow &window);
        private:
            static void GameLoop(sf::RenderWindow &window);
    
            static bool isExiting();
    
            enum ScreenState {before, splash1, splash2, splash3, menu, pause, playing, exit};
            static ScreenState currentState;
    };
    

    在Articx.cpp中,删除窗口的全局定义并修改Start()和Gameloop()以接受并使用传递的sf :: RenderWindow引用:

    void Articx::Start(sf::RenderWindow &window)
    {
        Message("Articx Engine 1.0 Initializing...");
    
        if(currentState != before)
            return;
    
        window.create(sf::VideoMode(800,600,32), "Articx Engine 1.0");
        currentState = playing;
    
        while (!isExiting())
        {
            Message("Engine Initialized");
            Articx::GameLoop(window);
        }
    
        window.close();
    }
    
    . . .
    
    void Articx::GameLoop(sf::RenderWindow &window)
    {
        . . .
    }
    

    现在运行它会正确显示窗口:

    enter image description here

    窗口似乎有一个无限循环打印“Engine Initialized”,但我留给你:-) .

相关问题