Is there possibly a way to take out the nested if
statements without losing the error reports? I am just learning SDL and would like to further simplify my code so that it is readable by me when I look at in a few days.
#include <SDL.h>
#include <iostream>
int main(int argc, char *argv[]) {
SDL_Window *window = nullptr; //the window
SDL_Surface *windowSurface = nullptr; //will store current window surface
SDL_Surface *imageSurface = nullptr; //will store image to be applied to the window
//inits video
if (SDL_Init(SDL_INIT_VIDEO) < 0)
std::cout << "Video Init Error: " << SDL_GetError() << std::endl;
//if error
else { //creates window
window = SDL_CreateWindow("Slime Runner Prelim Tests",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
if (window == NULL)
std::cout << "Window creation error: " << SDL_GetError() <<
std::endl; //if error
else { // if all is good with window creation.
//WINDOW HAS BEEN CREATED
windowSurface = SDL_GetWindowSurface(window);
imageSurface = SDL_LoadBMP("Images/Background.bmp");
if (imageSurface == NULL)
std::cout << "Image load error: " << SDL_GetError() <<
std::endl;
else {
SDL_BlitSurface(imageSurface, NULL, windowSurface, NULL);
SDL_UpdateWindowSurface(window);
}
}//end of window creation if
}//end of SDL_INIT_VIDEOs
SDL_Delay(4000);
SDL_FreeSurface(imageSurface);
imageSurface = nullptr;
SDL_DestroyWindow(window);
window = nullptr;
SDL_Quit();
return 0;
}
1 Answer 1
Is there possibly a way to take out the nested if statements without losing the error reports?
Use RAII to encapsulate your resources into objects that enforce the create/destroy pairing. You can write your own RAII wrapper objects or (better) use a resource factory that creates std::unique_ptr
/std::shared_ptr
's. A concrete factory for arbitrary SDL resources:
namespace sdl2 {
template <typename Creator, typename Destroyer, typename... Arguments>
auto make_resource(Creator c, Destroyer d, Arguments &&... args) {
auto r = c(std::forward<Arguments>(args)...);
if (!r) {
throw std::system_error(errno, std::generic_category(), SDL_GetError());
}
return std::unique_ptr<std::decay_t<decltype(*r)>, decltype(d)>(r, d);
}
} // namespace sdl2
This factory attempts to create the resource, checks to ensure it was created, and returns a unique_ptr
that destroys the resource correctly when the pointer goes out of scope. Specific helpers to provide higher levels of abstraction for resources like SDL_Window
, SDL_Texture
, SDL_Renderer
, etc, can be created like so:
namespace sdl2 {
using WindowPtr = std::unique_ptr<SDL_Window, decltype(&SDL_DestroyWindow)>;
WindowPtr make_window(const char *title, int x, int y, int w, int h,
std::uint32_t flags) {
return make_resource(SDL_CreateWindow, SDL_DestroyWindow, title, x, y, w, h,
flags);
}
} // namespace sdl2
You can write your own abstractions over SDL's C API to utilize some of the modern C++ constructs and ideally end with something like this:
int main() try {
auto window = sdl2::make_window("Slime Runner Prelim Tests",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
640, 480,
SDL_WINDOW_SHOWN);
auto screen = sdl2::get_surface(window);
auto image = sdl2::load_bitmap("Images/Background.tmp");
sdl2::blit_surface(image, nullptr, screen, nullptr);
sdl2::update_surface(window);
sdl2::delay(4s);
} catch (...) {
std::cout << "Error: " << error.what() << '\n';
}
Note: You don't have to use exceptions, but RAII does provide you with the flexibility to choose whichever error handling system you want (exceptions, checked errors, etc) while simplifying the cleanup process.
int main(int argc, char *argv[])
If you are not using argc
and argv
, omit them.
int main()
std::endl
Be aware of what std::endl
actually does. If you simply want to print a newline character, prefer '\n'
since it's both shorter and correct.
SDL_BlitSurface(imageSurface, NULL, windowSurface, NULL);
Use nullptr
instead of NULL
.