SDL2 |包装类访问冲突

Posted

技术标签:

【中文标题】SDL2 |包装类访问冲突【英文标题】:SDL2 | Wrapper class access violation 【发布时间】:2018-08-15 06:52:05 【问题描述】:

我一直在围绕一些 SDL2 功能制作一些非常简单的包装器。我创建了一个包装 SDL_Window* 的类和一个包装 SDL_Surface* 的类。

在我的 SDL_Surface 包装器 (SDL2::Surface) 中,构造函数接收 SDL2:::Window 包装器并将 SDL_Window*(通过 getter 调用)关联到 SDL2::Surface 中的 SDL_Surface* 成员变量。

然后,我有 SDL2::Surface::FillRect() 调用:

SDL_FillRect(Surface, NULL, SDL_MapRGB(Surface->format, 0xFF, 0x00, 0xFF));

在此构造下,我在调用 SDL_FillRect 时遇到访问冲突异常。但是,如果我将 SDL_Window*SDL_Surface 包装到一个包装类中,则从该类调用 SDL_FillRect 可以正常工作。

这两种方法可能有什么区别?

// Surface.h
namespace SDL2 
    class Window 
        private:
            SDL_Window* mWindow;
            int ScreenWidth = 640;
            int ScreenHeight = 480;

        public:
            Window();
            ~Window();
            SDL_Window* GetWindow();

    


// Surface.cpp
SDL2::Window::Window() 
    mWindow = SDL_CreateWindow("Breakout", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, ScreenWidth, ScreenHeight, SDL_WINDOW_SHOWN);


SDL2::Window::~Window() 
    SDL_DestroyWindow(mWindow);
        

// Surface.h
namespace SDL2 
    class Surface 
        private:
            SDL_Surface* Surface;

        public:
            Surface(SDL2::Window window);
            ~Surface();
            void FillRect();
            void Update(SDL2::Window window);
    


// Wrapper.cpp
SDL2::Surface::Surface(SDL2::Window window) 
    Surface = SDL_GetWindowSurface(window.GetWindow());
    

void SDL2::Surface::FillRect() 
        SDL_FillRect(Surface, NULL, SDL_MapRGB(Surface->format, 0xFF, 0x00, 0xFF)); // Access violation when this is called
        

void SDL2::Surface::Update(SDL2::Window window) 
    SDL_UpdateWindowSurface(window.GetWindow());


// main.cpp
#include <SDL.h>
#include <stdio.h>
#include "Wrapper.h"
#include "Window.h"

int main() 
    //Initialize SDL
    if (SDL_Init(SDL_INIT_VIDEO) < 0)
    
        printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
        return 1;
    

    SDL2::Window window = SDL2::Window();

    SDL2::Surface surface = SDL2::Surface(window);

    surface.FillRect();

    SDL_Delay(2000);

    return 0;

【问题讨论】:

也许您正在制作浅拷贝而没有意识到这一点,并且临时对象正在释放您的资源。我们需要看代码。 你有一些 rule-of-three 违规。 @HolyBlackCat,感谢您指出这一点 - 这对我来说是很好的做法。到目前为止,我想防止 SDL2::Surface 和 SDL2::Window 被复制,所以我将复制构造函数和复制赋值定义添加为私有,并将它们未定义。 【参考方案1】:
Surface(SDL2::Window window)
                    ^ missing &

您通过值传递您的Windows,导致~Window()Surface 构造函数返回后立即核对底层SDL_Window,从而使SDL_GetWindowSurface() 返回的表面无效。

改为通过引用传递它们:

#include <SDL.h>
#include <stdio.h>

namespace SDL2

class Window

private:
    SDL_Window* mWindow;
    int ScreenWidth = 640;
    int ScreenHeight = 480;

public:
    Window()
    
        mWindow = SDL_CreateWindow( "Breakout", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, ScreenWidth, ScreenHeight, SDL_WINDOW_SHOWN );
    

    ~Window()
    
        SDL_DestroyWindow( mWindow );
    

    SDL_Window* GetWindow()
    
        return mWindow;
    
;

class Surface

private:
    SDL_Surface* mSurface;

public:
    Surface( SDL2::Window& window )
    
        mSurface = SDL_GetWindowSurface( window.GetWindow() );
    

    void FillRect()
    
        SDL_FillRect( mSurface, NULL, SDL_MapRGB( mSurface->format, 0xFF, 0x00, 0xFF ) );
    

    void Update( SDL2::Window& window )
    
        SDL_UpdateWindowSurface( window.GetWindow() );
    
;


int main( int argc, char** argv )

    //Initialize SDL
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    
        printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
        return 1;
    

    SDL2::Window window = SDL2::Window();

    SDL2::Surface surface = SDL2::Surface( window );

    surface.FillRect();

    surface.Update( window );

    SDL_Delay( 2000 );

    return 0;

【讨论】:

以上是关于SDL2 |包装类访问冲突的主要内容,如果未能解决你的问题,请参考以下文章

python 这是一个包装FBX类,可用于访问和修改FBX场景

修改 Boost Python 包装类?

适配器模式

包装和可见性

Java中Math类和基本类型包装类的使用

如何在 cython 模块中使用外部包装类?