Interesting choice with SFML. Always curious to see what people choose for graphics when it comes to C++. I tried a simple game with that which worked alright, but then I wanted to port to Android and things didn't go very well. I switch to SDL2, where there's more official support for Android, but it's still not ... let's say ... enjoyable. Probably because I'm going against the Android grain in trying to avoid android-studio and gradle. I didn't need those for Windows64, Linux64, ARM, and I'd rather keep the same CMAKE, gui-free dev env for Android as well.
SFML can export to Android, but to me the biggest drawback is lack of Web export. In the current gamedev scene, web export is super popular for tiny games (specially for game jams, where it's just more convenience and also secure to share and try other games).
In today's world where so many tools offer web export (from libs to frameworks to engines), I can't justify learning a tool that doesn't support it.
An example: `std::shared_ptr<sf::RenderWindow> window;` - your main window really doesn't need multiple owners - it can be singly owned by `main()` or whatever the top level construct is for your game with `std::unique_ptr`. If you need to pass the window to some other function, do it by raw pointer or ref, signaling that "here's this object for you to use, but not own". `shared_ptr` should only be used for pointers that actually have multiple owners. The textures here might be a good example for this - you could implement a simple resource system that drops unused resources with `shared_ptr` + `weak_ptr`.
As for why - it's mostly around signaling intent and protecting against leaks. It's much easier to reason about ownership if you don't have to worry about some object deep inside your engine hierarchy holding a `shared_ptr` to the object that owns it. This can still happen with unique_ptr, but is much less likely.
Great explanation, as someone who is new to C++ and actively learning, these perspectives are invaluable.
I have been using some shared pointers in a personal project because of its ease of use but I aim to review and refactor this code to follow C++ idioms more appropriately. Thank you!
Shared ownership is a rare case, so in general using shared_ptr should already raise some suspicion. And in this case there is no reason any of the shared_ptr'ed things in the code need to be on the heap so no reason to even have a pointer in the first place.
Code like this is effectively what you get when you have someone that doesn't know how to write C++ but writes it anyway and uses pointers everywhere because they either read that C++ is pointer heavy (it's not) or have learned C++ through some course that is actually a course on algorithms and only uses C"++" as example language and is hence at best showing shitty C with iostream and classes straight out the 1980s. Then those people find the (correct) advice of using smart pointers instead of (owning!!!) raw pointers and just put shared_ptr everywhere without thinking about if there actually is a shared ownership to be expressed and/or if the heap allocation is even needed.
A shared pointer is one where ownership can be shared across any part of the application. That sounds great initially, as it assures the thing you’re pointing at will still be alive while you need it. In reality it creates a vague notion of ownership, where no one is responsible for object lifetime, because everyone is. This creates a “functional global” in your application per instance of your shared pointer class. The net effect is a more modern looking architectural morass.
shared_ptr<> is most useful for multithreaded applications where a pointer can be safely shared amongst many threads, where the last one to go out of scope will call delete on the object.
To do this safely the shared_ptr<> class maintains a reference count which is protected by a mutex. This is pretty inefficient if you never share a pointer across threads.
Better to use unique_ptr<> where the Thing that created it is also the Thing that's responsible for deleting it - after making sure that anything it's shared the pointer with is already safely destroyed (another thread, a collection or some other object).
std::shared_ptr doesn't use mutexes in any implementation I know of. They use atomic instructions for incrementing and decrementing the reference count, which are very fast.
I mean it's not bad but you start with a couple of files already packed with code and you don't explain all that. It is probably fine for someone who knows what these things are for but this kind of person can probably do away with the rest of the tutorial.
The sad thing is that there are tons of people doing this in a professional environment. auto and shared_ptr all the things. exceptions everywhere. RTTI. <cstdio> <cmath>.
The code looks fine to me. If you see the newer C++23 guides like Lospinoso's C++ book, auto, shared_ptr, braces default value initializations are all considered best practices now. The only major issue I see is that OP should have used references instead of shared_ptrs for some of the variables.
So I spent the last couple of hours on this. Pulled out all the shared_ptr and make_shared bollocks, played a couple of tricks with ld to embed the PNG images into the binary (since I don't do Windows or macOS, I'm OK with that), add some external references to these embedded images, created a CMakeFile that will figure out if you have SFML installed on the system etc.
Well... The video is 35 minutes in length, but you can tell it's been heavily edited. Even if you knew what you're doing you probably wouldn't be able to do it in 35 mins