Указатели класса C ++ и владение - PullRequest
0 голосов
/ 04 июня 2019

Итак, я воссоздаю Pong в C ++ (использование ncurses для терминальных переходов, поскольку попытка сделать это просто с консолью оказалась намного сложнее, чем я думал).Это что-то вроде "Обновить на C ++", так как это было давно, и я хочу заняться разработкой игр для хобби с использованием Unity.

Я подумал: «Что ж, я должен в LEAST сделать сначала простую игру на C ++, чтобы доказать, что я могу даже начать на Unity). Понг - очевидный выбор, когда вам нужно справиться: объекты, игровое состояние, столкновение, движениеVectors-ish.

В обновлении на C ++ мне пришлось искать много нового и напоминать себе о забытых вещах (прошло уже 10 лет с тех пор, как я коснулся C ++). Одна вещь, которую я не могуочень хорошо помню, это очень подробное описание указателей в отношении классов. (Кстати, очень простая версия с мячом и веслами / столкновением здесь: 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 ++).Если есть более правильный способ, который я хотел бы знать!

Мне также сказали, что, вероятно, лучше в любом случае передавать по ссылке в этих функциях, чтобы не использовать указатели и не создавать указатель вместе..

Ответы [ 2 ]

5 голосов
/ 04 июня 2019

Все это автоматические переменные.Их время жизни закончится, когда вы достигнете конца текущей области.Нет необходимости удалять их;это произойдет автоматически, как только вы достигнете конца текущей области.


Если вы хотите, чтобы ваш объект класса 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;
};
0 голосов
/ 04 июня 2019

Все переменные в вашем примере расположены в стеке.Они живут только до тех пор, пока scope находится в них. Куча используется только при использовании нового или эквивалентного интеллектуального указателя.

...