0

This is a continuation of my previous post: (Sorry for the chain of questions)

No appropriate default constructor available for std::unique_ptr

I encountered a similar error, this time with std::unique_ptr in an std::unordered_map container: (Sorry that I have to put the whole code)

class cGraphics
{
public:
    //  Creator functions
    std::unique_ptr<SDL_Window, decltype(&SDL_DestroyWindow)> Create_Window(int xWin, int yWin);
    std::unique_ptr<SDL_Renderer, decltype(&SDL_DestroyRenderer)> Create_Renderer();
    bool Create_TextureMap(std::string texid, std::string texres, int r, int g, int b);         //  Using helper function Create_Texture()

    //  ctor & dtor

    cGraphics(int xWin, int yWin, std::string texid, std::string texres);
    ~cGraphics();

    //  Rendering
    void ClearScreen();
    bool SetRendererDrawColor(int r, int g, int b, int opaque);
    void RenderTexture(std::string texres, int xDes, int yDes);
    bool Show();
private:
    std::unique_ptr<SDL_Window, decltype(&SDL_DestroyWindow)> m_Window;
    std::unique_ptr<SDL_Renderer, decltype(&SDL_DestroyRenderer)> m_Renderer;
    std::unordered_map<std::string, std::unique_ptr<SDL_Texture, decltype(&SDL_DestroyTexture)>> m_TextureMap;

    //  Private default ctor
    cGraphics() : m_Window(nullptr, SDL_DestroyWindow), m_Renderer(nullptr, SDL_DestroyRenderer) {}

    //  Creator helper
    SDL_Texture* CreateTextureRawPtr(std::string texres, int r, int g, int b);
    std::unique_ptr<SDL_Texture, decltype(&SDL_DestroyTexture)> CreateTexture(std::string texres, int r, int g, int b);
};

cGraphics::cGraphics(int xWin, int yWin, std::string texid, std::string texres) : cGraphics()
{
    SDL_Init(SDL_INIT_VIDEO);

    m_Window = Create_Window(xWin, yWin);
    m_Renderer = Create_Renderer();

    if (m_Window == nullptr || m_Renderer == nullptr)
    {
        throw "SDL_Window or SDL_Renderer not ready!";
    }

    /*if (m_Window == nullptr || m_Renderer == nullptr || !Create_TextureMap(texid, texres, 255, 255, 255))
    {
        throw "SDL_Window or SDL_Renderer not ready!";
    }*/
}

cGraphics::~cGraphics()
{
    IMG_Quit();
    SDL_Quit();
}

void cGraphics::ClearScreen()
{
    SDL_RenderClear(m_Renderer.get());
}

bool cGraphics::SetRendererDrawColor(int r, int g, int b, int opaque)
{
    SDL_SetRenderDrawColor(m_Renderer.get(), r, g, b, opaque);      //  Should use reset here
    return true;
}

void cGraphics::RenderTexture(std::string texres, int xDes, int yDes)
{
    SDL_Rect g_SrcRect = { 0, 0, 32, 32 };          //  hard-coded for test
    SDL_Rect g_DesRect = { xDes, yDes, 32, 32 };
    SDL_RenderCopy(m_Renderer.get(), m_TextureMap[texres].get(), &g_SrcRect, &g_DesRect);
}

bool cGraphics::Show()
{
    SDL_RenderPresent(m_Renderer.get());
}

std::unique_ptr<SDL_Window, decltype(&SDL_DestroyWindow)> cGraphics::Create_Window(int xWin, int yWin)
{
    return std::unique_ptr<SDL_Window, decltype(&SDL_DestroyWindow)>(SDL_CreateWindow("SDL Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, xWin, yWin, SDL_WINDOW_SHOWN), SDL_DestroyWindow);
}

std::unique_ptr<SDL_Renderer, decltype(&SDL_DestroyRenderer)> cGraphics::Create_Renderer()
{
    SDL_Renderer* temprenderer = SDL_CreateRenderer(m_Window.get(), -1, 0);
    SDL_SetRenderDrawColor(temprenderer, 255, 255, 255, 0xff);
    return std::unique_ptr<SDL_Renderer, decltype(&SDL_DestroyRenderer)>(temprenderer, SDL_DestroyRenderer);
}


bool cGraphics::Create_TextureMap(std::string texid, std::string texres, int r, int g, int b)
{
    m_TextureMap.emplace(texid, CreateTexture(texres, r, g, b));
    return true;
}

SDL_Texture* cGraphics::CreateTextureRawPtr(std::string texres, int r, int g, int b)
{
    SDL_Surface* temp = IMG_Load(texres.c_str());
    //Set color key
    SDL_SetColorKey(temp, SDL_TRUE,
        SDL_MapRGB(temp->format, r, g, b));

    SDL_Texture* pTexture = SDL_CreateTextureFromSurface(m_Renderer.get(), temp);

    SDL_FreeSurface(temp);
    return pTexture;
}

std::unique_ptr<SDL_Texture, decltype(&SDL_DestroyTexture)> cGraphics::CreateTexture(std::string texres, int r, int g, int b)
{
    return std::unique_ptr<SDL_Texture, decltype(&SDL_DestroyTexture)>(CreateTextureRawPtr(texres, r, g, b), SDL_DestroyTexture);
}

The error message is:

error C2512: 'std::unique_ptr<SDL_Texture,void (__cdecl *)(SDL_Texture *)>::unique_ptr': no appropriate default constructor available

This is definitely similar to the previous question, with one exception: That unique pointer is inside of a container. I'm thinking that maybe I can put that std::unique_ptr<SDL_Texture, decltype(&SDL_DestroyTexture)> in a wrapper class, and provide the compiler with a default ctor for the wrapper class. But this is definitely very cumbersome, and I'm not sure if there are better ways.

Another thing is that I'm using a lot of .get(), which I now understand to be wrong, because it only returns a copy of the raw pointer inside of the unique pointer. Maybe I should use .reset().

Nicholas Humphrey
  • 1,220
  • 1
  • 16
  • 33
  • 1
    What is the checklist of question you asked yourself when choosing to use unique-ptr vs the type itself, raw ptr, or sharedptr? I know "are you sure you are barking up the right tree?" responses can be annoying, but I dont often see people trying to make a collection of uniqueptr, that's counter to its purpose. unique_ptr is usually used to hand off ownership from something that allocates to a caller. – Christopher Pisz Jun 20 '18 at 22:07
  • Actually, you are right. I probably should use shared_ptr in this case as m_TextureMap contains all the tiles and this definitely should be shared instead of unique. I'm not sure if shared_ptr will give me the same error, will try it out. Thanks! – Nicholas Humphrey Jun 20 '18 at 22:11

0 Answers0