How to use smart pointers with SDL2 (SDL_RWops)? I want to write read savefile function with smart pointers and SDL2. I have little expirience with smart pointers and just want to ask is my code good, correct and no memory leaks.
this is my code:
std::shared_ptr&lt;SDL_RWops&gt; saveFile;

--
int GameEngine::ReadSave() {

        int Highlevel;

        //Open file for reading in binary
        saveFile = std::shared_ptr&lt;SDL_RWops&gt;(SDL_RWFromFile( &quot;data/save.txt&quot;, &quot;r&quot; ), SDL_RWclose);

        //File does not exist
        if( saveFile.get()  == NULL ){
                printf( &quot;Warning: Unable to open file! SDL Error: %s\n&quot;, SDL_GetError() );
                
                Highlevel = 0;

                //Create file for writing
                saveFile = std::shared_ptr&lt;SDL_RWops&gt;(SDL_RWFromFile( &quot;data/save.txt&quot;, &quot;w+&quot; ), SDL_RWclose);

                if( saveFile.get() != NULL ){
                        printf( &quot;New save file created!\n&quot; );

                        //Initialize data
                        SDL_RWwrite( saveFile.get(), &amp;Highlevel, sizeof(int), 1 );
                }
                else {
                        printf( &quot;Error: Unable to create savefile! SDL Error: %s\n&quot;, SDL_GetError() );
                }
        }
        else{
                //Load data
                printf( &quot;Reading save file...!\n&quot; );

                SDL_RWread( saveFile.get(), &amp;Highlevel, sizeof(int), 1 );
        }

        return Highlevel;
}
Your idea to wrap the result of SDL_RWFromFile in a smart pointer is a good idea. I recommend a few improvements:

Factor out the opening-and-wrapping operations into a named function. For example:
auto OpenFile(const char *fname, const char *mode) {
    return std::shared_ptr&lt;SDL_RWops&gt;(SDL_RWFromFile(fname, mode), SDL_RWclose);
}


if( saveFile.get()  == NULL ){

Your whitespace is all messed up here; and also, you should generally treat smart pointers the same way you'd treat regular pointers. Avoid using .get() and .reset() and so on, unless you have a specific reason you need to emphasize the &quot;object-ness&quot; of the smart pointer. Keep it simple by writing:
saveFile = OpenFile(&quot;data/save.txt&quot;, &quot;r&quot;);
if (saveFile == nullptr) {
    printf(&quot;Warning: Unable to open savefile! SDL Error: %s\n&quot;, SDL_GetError());
    Highlevel = 0;
    saveFile = OpenFile(&quot;data/save.txt&quot;, &quot;w+&quot;);
    if (saveFile == nullptr) {
        printf(&quot;Error: Unable to create savefile! SDL Error: %s\n&quot;, SDL_GetError());
    } else {
        printf(&quot;New save file created!\n&quot;);
        SDL_RWwrite(saveFile.get(), &amp;Highlevel, sizeof(Highlevel), 1);
    }
} else {
    printf(&quot;Reading save file...!\n&quot;);
    SDL_RWread(saveFile.get(), &amp;Highlevel, sizeof(Highlevel), 1);
}

I notice that you are not checking the return value of SDL_RWread for errors. That's not great.
Have you considered throwing an exception on failure, instead of using printf to report directly to the user? This would certainly streamline your code:
if (auto f = OpenFile(&quot;data/save.txt&quot;, &quot;r&quot;)) {
    printf(&quot;Reading save file...\n&quot;);
    if (SDL_RWread(f.get(), &amp;Highlevel, sizeof(Highlevel), 1) != 1) {
        throw std::runtime_error(std::string(&quot;Save file format error: &quot;) + SDL_GetError());
    }
} else if (auto f = OpenFile(&quot;data/save.txt&quot;, &quot;w+&quot;)) {
    printf(&quot;Writing new save file...\n&quot;);
    Highlevel = 0;
    SDL_RWwrite(f.get(), &amp;Highlevel, sizeof(Highlevel), 1);
} else {
    throw std::runtime_error(std::string(&quot;Unable to create save file: &quot;) + SDL_GetError());
}


Finally, shared_ptr is overkill here because you never have more than one &quot;owner&quot; of the open file. You should certainly rewrite OpenFile to return a unique_ptr — a type which you can still implicitly convert to shared_ptr if you do ever need shared ownership of the file. See &quot;OpenSSL client and server from scratch, part 1&quot;; it's basically this:
struct RWCloser { void operator()(SDL_RWops *p) const { SDL_RWclose(p); } };

using UniqueRWops = std::unique_ptr&lt;SDL_RWops, RWCloser&gt;;

UniqueRWops OpenFile(const char *fname, const char *mode) {
    return UniqueRWops(SDL_RWFromFile(fname, mode));
}