Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to best handle C++ object initialization: empty constructors or pointers?

I'm wondering what is the best way to go about object initialization and storage with regards to objects that have to have a relatively large scope / long lifetime. Let's say we have a GameEngine class that needs to initialize and hold a reference to a Window for rendering. The reference is needed throughout the program's lifetime and the window needs to know its dimensions, at least.

In Java, I'd do it like this:

// Declaration:
Window window;
// Initialization:
window = new Window(width, height);

I understood that in C++, the first would already call the default constructor of the Window class, hence be declaration and initialization. Having a window = Window(width, height); would therefore be assignment, throwing away the already existing object.

The first solution I could find was to use a pointer:

// GameEngine.hpp
class GameEngine {
    Window *window;
};

// Somewhere in GameEngine.cpp:
window = new Window(width, height);

But then again, I constantly read one should favor plain objects over pointers whenever possible and in fact, I got myself into a mess of pointers in no time, so I am looking for another way.

Another solution seems to design your objects to have a constructor without parameters and set up the object later on:

// GameEngine.hpp
class GameEngine {
    Window window;
};

// Somewhere in GameEngine.cpp
window.setWidth(width);
window.setHeight(height);

This works, but has a serious drawback: the object (at least in this case) could be in an inconsistent state, as trying to display the window without setting width/height would result in an error or crash. It does work for some objects, but for most it does not.

One way to avoid this would be to have default values. For example, the constructor for the Window class could look like this:

Window::Window(int width = 800, int height = 600) {}

Or even like that:

Window::Window() : width(DEFAULT_WIDTH), height(DEFAULT_HEIGHT) {}

But in many cases, default values will be hard to determine. Also, where should they be coming from? Should the Window class define DEFAULT_WIDTH and DEFAULT_HEIGHT? Or should I even do this?

// GameEngine.hpp
class GameEngine {
    static const int DEFAULT_WIDTH = 800;
    static const int DEFAULT_HEIGHT = 600;
    Window window(800,600);
};

But that seems bad, as I've read that you should not do any initialization in the header, only declaration, so the values of DEFAULT_WIDTH and DEFAULT_HEIGHT should not actually be known at this point (and only be initialized in the .cpp, correct?).

Am I missing an option? Or is it common in C++ to assume that the programmer should know what he's doing and take care of getting his objects in a consistent state before using them? When to use which approach?

like image 219
domsson Avatar asked Jun 03 '15 21:06

domsson


1 Answers

If you want to construct it only once and it can be done in the initialization of the class then you dont need a pointer. You can declare it as a member and initialize it in the constructor like so:

HPP

class Game
{
    private:
        Window window_;

    public:
        Game(int, int);
}

CPP

Game::Game(int width, int height) : window_(width, height)
{
}

This will construct the window object when you construct the Game object and it will persist until the Game object is destroyed. If you want to be able to construct it later or reconstruct it at any time then use a std::unique_ptr like so:

HPP

class Game
{
    private:
       std::unique_ptr<Window> window_;

    public:
        Game(int, int);
        void SomeMethod(int, int);

}

CPP

Game::Game(int width, int height)
{
    window_ = std::make_unique<Window>(width, height);
}

Game::SomeMethod(int width, int height)
{
    window_ = std::make_unique<Window>(width, height);
}

This will automatically delete the window when the Game object is destroyed and automatically delete the window each time you call std::make_unique to build a new one. Here is some doc on unique_ptr: http://en.cppreference.com/w/cpp/memory/unique_ptr

like image 69
Josh Edwards Avatar answered Nov 15 '22 16:11

Josh Edwards