1
\$\begingroup\$

I have recently learnt about RAII and exceptions and I have been trying to implement them into my code, but I have met an impasse.

With this code here what I am trying to do is manage everything that is being created so that there is nothing left over for when the program ends. I have deliberately set it so that media throws an exception. But before I continue on with more code, I am wondering if this general way of doing things is correct and if are there any other/better approaches to what I am doing.

The two classes that confuse me most are Media and Game. In their destructor, they have it stated that when they go out of scope. They should inform the console that they have gone out of scope, but it isn't currently doing that.

main.cpp

#include "Enemy.h"
#include "Media.h"
#include "Window.h"
#include "Game.h"

#include <SDL.h>
#include <iostream>

int main(int argc, char *args[])
{
    try
    {
        Window window;
        Media media;
        Game game;
    }
    catch (const std::exception &e)
    {
        std::cout << e.what();
        std::cout << "\nProgram failed.";
    }

    char c;
    std::cin >> c;
    return 0;
}

Window.h

#pragma once
#include <SDL.h>
#include <memory>
#include <string>
class Window
{
public:
    Window();
    ~Window();

    SDL_Window* getWindow() const { return m_window; }
    SDL_Surface* getWindowSurface() const { return m_windowSurface; }

    static constexpr int SCREEN_WIDTH = 800;
    static constexpr int SCREEN_HEIGHT = 800;

private:

    void createWindow();
    void CreateWindowSurface();
    SDL_Window* m_window = nullptr;
    SDL_Surface* m_windowSurface = nullptr;
};

Window.cpp

#include "Window.h"
#include <iostream>
Window::Window()
{
    createWindow();
    CreateWindowSurface();
}

Window::~Window()
{
    SDL_DestroyWindow(m_window);
    std::cout << "Window destroyed.\n";
}

void Window::createWindow()
{
    m_window = SDL_CreateWindow("Snake", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
    std::cout << "Window created.\n";
    if (m_window == nullptr) {
        throw(std::exception("Failed to initialize Window.\n"));
    }
}

void Window::CreateWindowSurface()
{
    m_windowSurface = SDL_GetWindowSurface(m_window);
    if (m_windowSurface == nullptr) {
        SDL_DestroyWindow(m_window);
        throw(std::exception("Failed to get window surface.\n!"));
    }
}

Media.h

#pragma once
#include <SDL.h>
class Media
{
public:
    Media();
    ~Media();

private:
    void loadSurface();

    SDL_Surface* m_playerSurface = nullptr;
};

Media.cpp

#include "Media.h"
#include <iostream>

Media::Media()
{
    loadSurface();
    //Load all other textures that are associated with the game
}

Media::~Media()
{
    std::cerr << "Media destroyed.\n";
}

void Media::loadSurface()
{
    m_playerSurface = SDL_LoadBMP("Origrimmar.bmp");
    if (m_playerSurface == nullptr) {
        throw(std::exception("Cannot load player texture"));
    }
}

Game.h

#pragma once
#include <SDL.h>
class Game
{
public:
    Game();
    ~Game();

};

Game.cpp

#include "Game.h"
#include <iostream>

Game::Game()
{
    std::cerr << "Game created.\n";
}

Game::~Game()
{
    std::cerr << "Game destroyed.\n";
}
\$\endgroup\$
2
\$\begingroup\$

I see some things that may help you improve your code.

Use all required #includes

The Media.cpp file uses a std::exception but is missing this line:

#include <exception>

Use std::runtime_error

The code in Media.cpp includes this line:

throw(std::exception("Cannot load player texture"));

However, that shouldn't compile because there is no constructor for std::exception that takes a const char * argument. Instead, that should probably be this:

throw(std::runtime_error("Cannot load player texture"));

Don't forget SDL_Init

Any SDL2 program must call SDL_Init but yours doesn't. To fix that, I'd recommend adding an SDL object as illustrated on the SDL Wiki. It simply makes an object whose constructor calls SDL_Init and whose destructor calls SDL_Quit while translating SDL error into C++ exceptions.

Remember object scoping rules

Right now, your objects are all declared within the try block. This also means that they only exist within that block because of C++ scoping rules. In a real version of the program, you'd either need to have something happen inside that try block.

\$\endgroup\$
  • \$\begingroup\$ std::exception with a constructor taking a string is a Microsoft extension: msdn.microsoft.com/en-us/library/c4ts6d5a.aspx \$\endgroup\$ – glampert Mar 6 '16 at 18:19
  • 1
    \$\begingroup\$ @glampert: The only thing worse than non-standard non-portable code that doesn't compile is non-standard non-portable code that does! \$\endgroup\$ – Edward Mar 6 '16 at 18:25
  • \$\begingroup\$ Haha, true. I wan't endorsing it though, just informing ;) \$\endgroup\$ – glampert Mar 6 '16 at 18:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.