3
#include <vector>

enum ListOfGameStates
{
    // List of game states
};

class GameState()
{
    public:
        GameStates(); // Initializes protected (global) variables
        virtual ListOfGameStates run() = 0;
    protected:
        // Heavyweigh resource managers containing all resources and other global vars
}

class GameStateManager()
{
    public:
        GameStateManager();  // Creates all game states
        ~GameStateManager(); // Deletes all game states
        void run();          // Switches from one state to another state
    private:
        // A vector of raw pointers to game states. GameState is a base class.
        std::vector<GameState*> game_states_container;
}

I want to get rid off raw pointers so that I could have no worries about exceptions and clean-up. Is there an easy simple solution (I am a really dumb teen) or is it not worth it? Thanks!

  • Sorry, I was confused because 'push_back' wouldn't work. Now it's fine –  Feb 01 '15 at 12:58
  • 1
    Generally, it is probably a good idea to include what "wouldn't work" in your question. – Chris Drew Feb 01 '15 at 12:59
  • 1
    Looks like your `GameState` class needs a `virtual` destructor. – Galik Feb 01 '15 at 13:00
  • @Galik Why? Game states have no pointers, all big objects are global. Others are self-destroying smart classes. –  Feb 01 '15 at 13:03
  • 2
    `GameState` has a pure virtual function meaning you will only be using subclasses and those subclasses will be deleted (by the smart pointer) from a base pointer. Without a virtual dtor that's undefined behavior. – Galik Feb 01 '15 at 13:04
  • Good books: https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list – Galik Feb 01 '15 at 13:06

1 Answers1

7

Simply change your vector to:

std::vector<std::unique_ptr<GameState>> game_states_container;

And get rid of any delete in your destructor. In fact you can probably get rid of the destructor entirely unless it has other jobs to do.

unique_ptr is not copyable but it is movable so it is worth having some understanding of C++11 move-semantics. When you want to add a unique_ptr to your container you can use push_back providing you pass a temporary, e.g the return value of a function:

game_states_container.push_back(createGameState());
game_states_container.push_back(std::make_unique<GameStateA>());  // C++14

Or if you have a local unique_ptr variable you can use std::move to move it into the vector:

std::unique_ptr<GameState> game_state = std::make_unique<GameStateA>();  // C++14
// auto game_state = std::unique_ptr<GameState>(new GameStateA);  // C++11
...
game_states_container.push_back(std::move(game_state));

It is good practice to put the raw pointers in unique_ptr as soon as you new them (or preferably use std::make_unique). Otherwise, if an exception is thrown between allocation and wrapping in unique_ptr you have a memory leak.

It is unrelated to unique_ptr but your GameState class should have a virtual destructor.

Live demo

Community
  • 1
  • 1
Chris Drew
  • 14,926
  • 3
  • 34
  • 54
  • Try it and see. Also read your C++11 book to the end before continuing. – Lightness Races in Orbit Feb 01 '15 at 12:57
  • I guess I need another book. –  Feb 01 '15 at 13:00
  • 4
    Actually, Chris, your answer is now a bit misleading: `push_back` will work just fine on `unique_ptr`, even without `std::move` – as long as the object being pushed is a temporary. `emplace_back` isn’t necessary because `unique_ptr` is noncopyable, it’s necessary because there’s no implicit conversion from a raw pointer to `std::unique_ptr`. – Konrad Rudolph Feb 01 '15 at 13:01
  • @KonradRudolph Hope that is less misleading now. – Chris Drew Feb 01 '15 at 13:10
  • 1
    @Chris It’s perfect now. – Konrad Rudolph Feb 01 '15 at 13:11
  • Dunno if its worth mentioning, but emplace_back forwards its args to the fundamental T constructor when emplacement is being done. Thus the equivalent to the other methods of insertion isn't `emplace_back()`, its `emplace_back(new GameStateDerivative);` The constructor for `std::unique_ptr<>` will receive the allocated object and take ownership, avoiding the need to later `reset(new GameStateDerivative)` (which you can still do anyway, of course). Also, `make_unique` is a C++14 feature, for those still in the C++11 trenches (i.e. most of us). – WhozCraig Feb 01 '15 at 13:17
  • @WhozCraig Now we have `make_unique` (which is available Visual Studio 2013) I avoid using `new` entirely and prefer `push_back(std::make_unique())`. – Chris Drew Feb 01 '15 at 13:25
  • Yeah, "now we have make_unique" - unfortunately, "we* don't yet. Jeezo I'm still stuck in the half-baked 03x derivation MS spun with VS2010 at work (yeah, ugh). Company entrenchment FTL. * – WhozCraig Feb 01 '15 at 13:29
  • @WhozCraig, but what does `emplace_back(new GameStateDerivative)` do if the vector tries to reallocate and throws `bad_alloc`? The constructor for `unique_ptr` only takes ownership if the vector gets far enough to use that constructor. See http://stackoverflow.com/a/19414387/981959 – Jonathan Wakely Feb 01 '15 at 14:10
  • 1
    @JonathanWakely I think I will get rid of the `emplace_back` suggestion entirely I can't think of a good reason for using it in this context. – Chris Drew Feb 01 '15 at 14:27
  • @ChrisDrew, agreed. `emplace_back` is useful to avoid a temporary, but shouldn't be used just to perform an implicit conversion that would fail to compile otherwise. – Jonathan Wakely Feb 01 '15 at 14:49