如何最好地处理C++对象初始化:空构造函数或指针?

dom*_*son 5 c++ pointers initialization declaration object

我想知道对于必须具有相对较大范围/长寿命的对象,对象初始化和存储的最佳方法是什么.假设我们有一个GameEngine类需要初始化并保持Window对渲染的引用.整个程序的生命周期都需要引用,窗口至少需要知道它的尺寸.

在Java中,我会这样做:

// Declaration:
Window window;
// Initialization:
window = new Window(width, height);
Run Code Online (Sandbox Code Playgroud)

我理解在C++中,第一个已经调用了Window类的默认构造函数,因此是声明初始化.window = Window(width, height);因此,有一个将分配,扔掉已经存在的对象.

我能找到的第一个解决方案是使用指针:

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

// Somewhere in GameEngine.cpp:
window = new Window(width, height);
Run Code Online (Sandbox Code Playgroud)

但话说回来,我经常读到一个人应该尽可能地支持普通对象而不是指针,事实上,我立刻陷入了一堆乱七八糟的指针,所以我正在寻找另一种方式.

另一种解决方案似乎是设计你的对象以获得没有参数的构造函数,并在以后设置对象:

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

// Somewhere in GameEngine.cpp
window.setWidth(width);
window.setHeight(height);
Run Code Online (Sandbox Code Playgroud)

这有效,但有一个严重的缺点:对象(至少在这种情况下)可能处于不一致状态,因为试图在没有设置宽度/高度的情况下显示窗口会导致错误或崩溃.它确实适用于某些对象,但对大多数情况它没有.

避免这种情况的一种方法是使用默认值.例如,Window类的构造函数可能如下所示:

Window::Window(int width = 800, int height = 600) {}
Run Code Online (Sandbox Code Playgroud)

甚至是这样的:

Window::Window() : width(DEFAULT_WIDTH), height(DEFAULT_HEIGHT) {}
Run Code Online (Sandbox Code Playgroud)

但在许多情况下,默认值很难确定.此外,他们应该从哪里来?如果Window类的定义DEFAULT_WIDTHDEFAULT_HEIGHT或者我应该这样做?

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

但这看起来很糟糕,因为我已经读过你不应该在标题中进行任何初始化,只能声明,所以此时的值DEFAULT_WIDTHDEFAULT_HEIGHT实际上不应该知道(并且只能在.cpp中初始化,对吗?) .

我错过了一个选项吗?或者在C++中常见的是假设程序员应该知道他在做什么并在使用之前将其对象保持在一致状态?何时使用哪种方法?

小智 5

如果您只想构造它一次并且可以在类的初始化中完成,那么您不需要指针。您可以将其声明为成员并在构造函数中对其进行初始化,如下所示:

高压泵

class Game
{
    private:
        Window window_;

    public:
        Game(int, int);
}
Run Code Online (Sandbox Code Playgroud)

CPP

Game::Game(int width, int height) : window_(width, height)
{
}
Run Code Online (Sandbox Code Playgroud)

这将在您构造 Game 对象时构造 window 对象,并且它将一直持续到 Game 对象被销毁。如果您希望能够稍后构造它或随时重建它,那么使用 std::unique_ptr 像这样:

高压泵

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

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

}
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

这将在 Game 对象被销毁时自动删除窗口,并在每次调用 std::make_unique 构建新窗口时自动删除窗口。这是关于 unique_ptr 的一些文档:http : //en.cppreference.com/w/cpp/memory/unique_ptr