简体   繁体   English

是否可以将SDL2与智能指针一起使用?

[英]Is it possible to use SDL2 with smart pointers?

I have this line of code 我有这行代码

//std::unique_ptr<SDL_Window> _window_; // this is somewhere else...
_window_ = std::make_unique<SDL_Window>(SDL_CreateWindow("SDL Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, _WIDTH_, _HEIGHT_, SDL_WINDOW_SHOWN));

it produces the following compiler error 它会产生以下编译器错误

In file included from /usr/include/c++/6/memory:81:0,
                 from /home/user/prj/src/main.cpp:4:
/usr/include/c++/6/bits/unique_ptr.h: In instantiation of ‘typename 
std::_MakeUniq<_Tp>::__single_object std::make_unique(_Args&& ...) [with _Tp = SDL_Window; _Args = {SDL_Window*}; typename 
std::_MakeUniq<_Tp>::__single_object = std::unique_ptr<SDL_Window>]’:
/home/user/prj/src/main.cpp:36:170:   required from here
/usr/include/c++/6/bits/unique_ptr.h:791:30: error: invalid use of incomplete type ‘struct SDL_Window’
     { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }

why? 为什么? (It works fine without smart pointers, so my guess is I didn't understand the syntax and this is trivial to fix. Will add source and CMakeLists.txt below.) (没有智能指针它工作正常,所以我的猜测是我不理解语法,这很容易修复。将在下面添加源代码和CMakeLists.txt 。)

CMakeLists.txt 的CMakeLists.txt

cmake_minimum_required(VERSION 3.7)
project(prj)

find_package(SDL2 REQUIRED)
include_directories(prj ${SDL2_INCLUDE_DIRS})

add_executable(prj main.cpp)
target_link_libraries(prj ${SDL2_LIBRARIES})

main.cpp main.cpp中

#include "SDL.h"
#include <memory>
#include <iostream>
#include <fstream>
#include <cstdint>

class Window
{

    public:

    Window()
        : _window_{nullptr}
        , _surface_{nullptr}
    {
        if(SDL_Init(SDL_INIT_VIDEO) < 0)
        {
            std::cerr << SDL_GetError() << std::endl;
        }
        else
        {
            _window_ = std::make_unique<SDL_Window>(SDL_CreateWindow("SDL Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, _WIDTH_, _HEIGHT_, SDL_WINDOW_SHOWN));

            if(_window_ == nullptr)
            {
                std::cerr << SDL_GetError() << std::endl;
            }
            else
            {
                _surface_ = std::make_unique<SDL_Surface>(SDL_GetWindowSurface(_window_.get()));
                SDL_FillRect(_surface_.get(), nullptr, SDL_MapRGB(_surface_->format, 0xFF, 0xFF, 0xFF));
                SDL_UpdateWindowSurface(_window_.get());
                SDL_Delay(1000);
            }
        }
    }

    ~Window()
    {
        SDL_DestroyWindow(_window_.get());
        SDL_Quit();
    }

    private:

    const int32_t _WIDTH_{600};
    const int32_t _HEIGHT_{400};

    std::unique_ptr<SDL_Window> _window_;
    std::unique_ptr<SDL_Surface> _surface_;

};


int main(int argc, char* argv[])
{
    Window window;
    return 0;
}

Solution

Finally figured out the answer with a lot of trial and error, so will explain the solution here. 最后通过大量试验和错误找到了答案,因此将在此解释解决方案。

This is the correct syntax: 这是正确的语法:

// first define the unique_ptr as member of class
std::unique_ptr<SDL_Window, decltype(&SDL_DestroyWindow)> _window_;

// second, initialize in the member initialization list of class constructor
// probably don't need to do this if not embedding as member of class
class_name()
    : _window_(nullptr, SDL_DestroyWindow)
{
    // blaa blaa SDL code etc
    _window_.reset(SDL_CreateWindow("SDL Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN));
}

// finally we need to be able to delete
// but this is handled automatically

Explanation 说明

When we add the unique_ptr as a data member, we need to give both the type SDL_Window and the "deleter function format / syntax", becuase an ordinary delete call is not correct. 当我们添加unique_ptr作为数据成员时,我们需要同时给出类型SDL_Window和“删除函数格式/语法”,因为普通的delete调用不正确。 We use decltype to automatically construct the correct deleter format from the deleter function. 我们使用decltype从deleter函数自动构造正确的删除器格式。 (Perhaps not the most accurate explanation.) In a way, decltype is somewhat like auto... (也许不是最准确的解释。)在某种程度上, decltype有点像自动......

std::unique_ptr<SDL_Window, decltype(&SDL_DestroyWindow)> _window_;

This object must be initialized. 必须初始化此对象。 We do this in the constructor. 我们在构造函数中执行此操作。 We set the pointer to nullptr (because we do not want to initialize it before initializing SDL2) and we also set the deleter function. 我们将指针设置为nullptr (因为我们不想在初始化SDL2之前初始化它),我们还设置了删除函数。

: _window_(nullptr, SDL_DestroyWindow)

After initializing SDL, we then want to create a window. 在初始化SDL之后,我们想要创建一个窗口。 This is done most easily by calling the smart pointer reset() function. 通过调用智能指针reset()函数可以轻松完成此操作。 We pass it a new pointer returned by the function which creates the window. 我们传递一个由创建窗口的函数返回的新指针。

_window_.reset(SDL_CreateWindow(...));

Done. 完成。 Took a long time to figure out but makes sense now. 花了很长时间才弄清楚但现在才有意义。 References 参考

http://en.cppreference.com/w/cpp/memory/unique_ptr http://en.cppreference.com/w/cpp/memory/unique_ptr

Why does my unique_ptr think is has a null function pointer deleter? 为什么我的unique_ptr认为有一个空函数指针删除器?

What's wrong with this initialization of unique_ptr? 这个unique_ptr的初始化有什么问题?

Those structures are opaque data structures , you don't have the full definition of them. 这些结构是不透明的数据结构 ,您没有完整的定义。 That means, among other things, that the default std::unique_ptr deleter don't know how to "delete" the structures. 这意味着,除其他外,默认的std::unique_ptr删除器不知道如何“删除”结构。

You need to provide your own custom deleter. 您需要提供自己的自定义删除器。 For SDL_Window it's the SDL_DestroyWindow function. 对于SDL_Window它是SDL_DestroyWindow函数。

A SDL Windows is destroyed using SDL_DestroyWindow, not plain delete, like the unique_ptr's default deleter does. SDL Windows使用SDL_DestroyWindow销毁,而不是普通删除,就像unique_ptr的默认删除器一样。 You need to supply a custom deleter to unique_ptr, which will call SDL_DestroyWindow. 您需要为unique_ptr提供自定义删除器,它将调用SDL_DestroyWindow。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM