Правильный синтаксис для обновления векторных элементов классов

avatar
tothemax
9 августа 2021 в 04:27
151
1
0

У меня есть вопрос относительно классов и того, как можно обновить их участников.

Итак, у меня есть простой класс

class Player
{
public:
    Player();
    std::vector <std::string> hand = {"r4", "r1", "g5"};
};

Player::Player()
{

}

и я добавил экземпляры этих классов в другой вектор

std::vector <Player> players;

            Player p1;
            Player p2;

            players.push_back(p1);
            players.push_back(p2);

Но затем я пытаюсь обновить векторы инициализированных классов внутри вектора, хранящего классы

            //doesn't work
            //p1.hand.push_back("test1");
            //p2.hand.push_back("test2");

            //works
            players[0].hand.push_back("test1");
            players[1].hand.push_back("test2");

       for (int i = 0; i < 2; i++) 
            std::cout << players[i].hand[(players[i].hand.size() - 1)] << std::endl;

Я не понимаю, почему он не добавляет тестовые строки к векторам классов в массиве игроков с помощью первого метода. Это потому, что это не тот экземпляр класса, который я впервые инициализировал? Если бы кто-то мог прояснить это для меня, это было бы очень признательно. Спасибо!

Источник
tothemax
9 августа 2021 в 04:43
0

Хорошо, это имеет смысл, спасибо. Но из любопытства, могу ли я поместить оригинал в вектор?

PaulMcKenzie
9 августа 2021 в 04:45
0

Измените свой способ написания кода при работе с C++. C++ — это не Java или JavaScript. Какова веская причина иметь оригинальные экземпляры? Если они есть в векторе, локальные версии все равно выйдут за рамки.

Frank
9 августа 2021 в 04:45
0

@tothemax, есть несколько способов сделать это. std::vector<std::reference_wrapper<Player>> будет "самым чистым", но вектор ссылок, не являющихся владельцами, редко бывает правильным.

tothemax
9 августа 2021 в 04:53
0

@PaulMcKenzie Да, ха-ха, на самом деле я использую только JavaScript, поэтому я пытаюсь понять, как это работает на C ++. Есть ли у вас какие-либо рекомендации книг или ресурсов, которые могли бы облегчить этот переход?

Frank
9 августа 2021 в 04:55
1

@tothemax Вы можете начать здесь: coderhelper.com/questions/388242/…

PaulMcKenzie
9 августа 2021 в 04:57
0

Я думаю, что нужно думать о ссылках, а не о значениях. С++ работает по-другому в этом отношении. Локальные версии выйдут за пределы области действия и будут уничтожены — копии в векторе останутся на месте (до тех пор, пока сам вектор не выйдет за пределы области действия). Кроме того, в C++ есть семантика перемещения, поэтому вполне возможно, что любые опасения по поводу эффективности, когда речь идет о времени, будут спорными.

tothemax
9 августа 2021 в 05:11
0

Да, я думаю, что постепенно начинаю обдумывать это, когда изучаю С++. Я буду помнить об этом, когда буду пытаться перенастроить свой мозг на этот язык.

Ответы (1)

avatar
Frank
9 августа 2021 в 04:42
3

В C++ (в основном) нет двойственности между типами значений и ссылочными типами. Все является значением, если не указано иное.

std::vector<Player> — это вектор экземпляров Player, а не список ссылок на экземпляры Player. Поэтому, когда вы выполняете players.push_back(p1);, это должно создать копию p1, чтобы экземпляр Player в векторе принадлежал ему.

Есть способы получить векторы ссылок, но это редко бывает правильным. Проблема с контейнерами ссылок, не являющихся владельцами, заключается в том, что вы должны каким-то образом быть абсолютно уверены, что каждый отдельный экземпляр, на который ссылается контейнер, переживет сам контейнер, а это может быть очень сложно.

В таком случае, как ваш, более типичным подходом было бы сделать вектор владельцем экземпляров. И если вам абсолютно необходимо иметь p1 и p2, они могут быть ссылками на переменные, указывающими на него:

// Initialize the vector with 2 default-constructed players
std::vector <Player> players(2);

// ...

{
  Player& p1 = players[0];

  p1.hand.push_back("test1");
  p1.hand.push_back("test2");
  p1.hand.push_back("test3");
}

Однако нужно быть осторожным, так как p1 и p2 станут недействительными, если вы измените размер вектора.

PaulMcKenzie
9 августа 2021 в 04:44
0

Проблема со ссылками на элементы вектора заключается в том, что при изменении размера вектора эти ссылки становятся недействительными.

tothemax
9 августа 2021 в 04:57
0

Хорошо, это помогло многое прояснить, ценю комментарий. Хотя, учитывая, что изменение размера вектора сделает элементы недействительными, будет ли это плохой практикой или для этого будет более подходящим использование статического массива?

Frank
9 августа 2021 в 05:08
1

@tothemax Переход к std::array изменился бы с «вы не должны изменять размер» на «вы не можете изменять размер». Но реальный ответ заключается в том, что ссылки на локальные переменные должны быть временными. Они должны существовать ровно столько времени, сколько вам нужно, что обычно ограничивается небольшим блоком кода, в котором изменение размера не происходит.