【问题标题】:C++ Class Pointers and ownershipC++ 类指针和所有权
【发布时间】:2019-06-04 19:55:45
【问题描述】:

所以我在 C++ 中重新创建了 Pong(使用 ncurses 进行终端 hijinks,因为尝试仅使用控制台进行操作被证明比我想象的要困难得多)。这有点像是“刷新 C++”,因为它已经有一段时间了,我想使用 Unity 进行一些爱好游戏开发。

我想“我至少应该先用 C++ 制作一个简单的游戏,以证明我什至可以从 Unity 开始)。Pong 是一个显而易见的选择,因为您需要处理:对象、游戏状态、碰撞、运动矢量-ish .

在刷新 C++ 的过程中,我不得不查找很多更新的东西,并提醒自己被遗忘的东西(我接触 C++ 已经 10 年了)。我不太记得的一件事是关于类的指针的私密细节。 (顺便说一句,这里有一个非常基本的带有球和桨/碰撞的版本:https://pastebin.com/5NHjEjxX 到目前为止我只花了几个小时)。

这里显示了我不太记得的一件事:

const int boardWidth = 60;
const int boardHeight = 12;
Ball ball = Ball(-1,1,(boardWidth/2),(boardHeight/2));
Ball *p_ball = &ball;
Paddle paddle1 = {4,(boardHeight/2),3};
Paddle *p_paddle1 = &paddle1;
Paddle paddle2 = {(boardWidth-4), (boardHeight/2),3};
Paddle *p_paddle2 = &paddle2;
Board board; 

(这是在 Game 类初始化中。虽然我有点想知道是否应该将它放在构造函数中)。尽管如此....特别是当我声明Ball ball = Ball(-1,1,(boardWidth/2),(boardHeight/2));Paddle paddle1 = {4,(boardHeight/2),3}; 时,这些项目在内存中“坐在”哪里?我假设堆?另外,我将如何以正确的方式删除这些(例如球出界,我需要创建一个新球?)

我知道有一些关于所有权的事情......我觉得这是使用 & 的错误方式,因为例如 p_ball 实际上不会“拥有”该类,而只是能够引用它对吗? (我认为有一个术语“智能指针”,但上次我接触 C++ 时还没有真正出现)。如果有更合适的方法我很想知道!

我还被告知,无论如何,在这些函数中通过引用传递可能会更好,以避免使用指针并避免一起创建指针。

【问题讨论】:

  • Ball ball = Ball(…) 球在堆栈上,但它的组件可能在堆上,也可能不在堆上。使用调试器和Ball 的源代码来检查它并了解发生了什么。 p_ball 只是一个指向球的指针,所以也在堆栈中。
  • 你被告知的是很好的建议。在遇到一些没有更简单解决方案的问题之前,不要乱用指针。也许如果您确实认为自己遇到过这种情况,请询问处理它的最佳方法。 (可能是通过引用,但也可能是别的东西。)
  • 另外,当球出界时,您可能不需要删除球。您可以简单地创建一个新的临时球,并将旧球设置为等于新球,然后让新球超出范围。如果您在游戏中跟踪回合并且从第 4 回合转到第 5 回合,则不会删除旧的回合计数器并创建一个新的设置为 5 的计数器——您只需将现有的圆形对象设置为 5。同样带球的东西。尽可能尝试处理值。

标签: c++ pointers lifetime


【解决方案1】:

所有这些都是自动变量。当您到达当前范围的末尾时,它们的生命周期将结束。无需删除它们;一旦您到达当前范围的末尾,这将自动发生。


如果您希望您的 Game 类对象拥有球、桨和板,那么拥有成员范围对他们来说是有意义的。即

class Game {
public:
    static const int BOARD_WIDTH = 60;
    static const int BOARD_HEIGHT = 12;

    Game()
        : ball{-1, 1, BOARD_WIDTH / 2, BOARD_HEIGHT / 2},
          paddle1{4, BOARD_HEIGHT / 2, 3},
          paddle2{BOARD_WIDTH - 4, BOARD_HEIGHT / 2, 3}
    {}

private:
    Ball ball;
    Paddle paddle1;
    Paddle paddle2;
    Board board;
};

这些成员对象将共享Game 对象的生命周期。


指针只是指向其他对象的对象。它们不会影响它们指向的对象的生命周期。例如,您可以从方法返回指向对象成员的指针。请注意您的指针不会比它们指向的对象寿命更长。

如果您想让Game 类包含指向其他对象的指针,那么您需要自己管理这些其他对象的生命周期。例如,您可以动态分配它们。与将对象直接包含在 Game 对象中相比,这几乎没有什么优势,而且增加了相当多的复杂性和开销。

这里我使用std::unique_ptr 来做内存管理:

class Game {
public:
    static const int BOARD_WIDTH = 60;
    static const int BOARD_HEIGHT = 12;

    Game()
        : ball{std::make_unique<Ball>(-1, 1, BOARD_WIDTH / 2, BOARD_HEIGHT / 2)},
          paddle1{std::make_unique<Paddle>(4, BOARD_HEIGHT / 2, 3)},
          paddle2{std::make_unique<Paddle>(BOARD_WIDTH - 4, BOARD_HEIGHT / 2, 3)},
          board{std::make_unique<Board>()}
    {}

    // Copying is implicitly disallowed since std::unique_ptr is non-copyable.
    // You could implement a copy constructor and copy assignment operator to
    // do a deep copy

private:
    std::unique_ptr<Ball> ball;
    std::unique_ptr<Paddle> paddle1;
    std::unique_ptr<Paddle> paddle2;
    std::unique_ptr<Board> board;
};

如果您真的愿意,也可以手动进行内存管理,但这样做几乎没有好处:

class Game {
public:
    static const int BOARD_WIDTH = 60;
    static const int BOARD_HEIGHT = 12;

    Game()
        : ball{new Ball(-1, 1, BOARD_WIDTH / 2, BOARD_HEIGHT / 2)},
          paddle1{new Paddle(4, BOARD_HEIGHT / 2, 3)},
          paddle2{new Paddle(BOARD_WIDTH - 4, BOARD_HEIGHT / 2, 3)},
          board{new Board()}
    {}

    // You must implement these yourself to do a deep copy when doing manual
    // memory management.  I've opted to delete them to disallow copying a Game object
    Game(const Game&) = delete;
    Game& operator=(const Game&) = delete;

    ~Game() {
        // every instance of 'new' must have exactly one matching 'delete'
        delete board;
        delete paddle2;
        delete paddle1;
        delete ball;
    }

private:
    Ball* ball;
    Paddle* paddle1;
    Paddle* paddle2;
    Board* board;
};

【讨论】:

  • 如果我将它们作为指针,它会以同样的方式完成吗? (或者在这种情况下最好只使用方法的引用)
  • 非常感谢,这对您有很大帮助!那里的 C++ 信息非常分散,示例可能彼此非常不同。
【解决方案2】:

您示例中的所有变量都位于堆栈中。它们只存在于它们所在的 scope 中。只有在使用 new 或等效的智能指针时才会使用堆。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-07
    • 2013-03-21
    • 2016-12-30
    • 1970-01-01
    • 2020-07-28
    • 2019-02-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多