Я пытаюсь создать сеть пользовательского class Tile внутри другого class Board, в котором хранится std::array<std::shared_ptr<Tile>, 34>. Я использую std::shared_ptr<Tile> объекты внутри class Tile, чтобы показать, какие узлы связаны. Однако, когда я инициализирую каждый из 34 объектов Tile, еще не инициализированные объекты, включенные в список, не обновляются с nullptr на свою собственную ссылку.
#include <memory>
#include <array>
#include <cstddef>
struct Tile;
template <const std::size_t N> using TileLink = std::array<const std::shared_ptr<const Tile>, N>;
template <const std::size_t N> using TileArray = std::array<std::shared_ptr<const Tile>, N>;
struct Tile {
/* surrounding tiles */
const std::size_t ID;
const std::size_t num_adj;
const TileLink<6> adjacent;
Tile (std::size_t id, std::size_t n, const TileLink<6> & arr) : ID (id), num_adj (n), adjacent (arr) { }
~Tile (void) = default;
};
class Board {
private:
TileArray<34> tiles;
public:
Board (void);
~Board (void) = default;
};
Board :: Board (void) {
/* Column 1 */
tiles[0] = std::make_shared<Tile> ( 0, 3, TileLink<6>{ tiles[1], tiles[4], tiles[5], nullptr, nullptr, nullptr });
tiles[1] = std::make_shared<Tile> ( 1, 4, TileLink<6>{ tiles[0], tiles[2], tiles[5], tiles[6], nullptr, nullptr });
tiles[2] = std::make_shared<Tile> ( 2, 3, TileLink<6>{ tiles[1], tiles[6], tiles[7], nullptr, nullptr, nullptr });
/* Column 2 */
tiles[3] = std::make_shared<Tile> ( 3, 2, TileLink<6>{ tiles[4], tiles[9], nullptr, nullptr, nullptr, nullptr });
tiles[4] = std::make_shared<Tile> ( 4, 5, TileLink<6>{ tiles[0], tiles[3], tiles[5], tiles[9], tiles[10], nullptr });
tiles[5] = std::make_shared<Tile> ( 5, 6, TileLink<6>{ tiles[0], tiles[1], tiles[4], tiles[6], tiles[10], tiles[11] });
tiles[6] = std::make_shared<Tile> ( 6, 6, TileLink<6>{ tiles[1], tiles[2], tiles[5], tiles[7], tiles[11], tiles[12] });
tiles[7] = std::make_shared<Tile> ( 7, 5, TileLink<6>{ tiles[2], tiles[6], tiles[8], tiles[12], tiles[13], nullptr });
tiles[8] = std::make_shared<Tile> ( 8, 2, TileLink<6>{ tiles[7], tiles[13], nullptr, nullptr, nullptr, nullptr });
/* Columns 4 - 6 */
...
...
...
/* Column 7 */
tiles[31] = std::make_shared<Tile> (31, 3, TileLink<6>{ tiles[26], tiles[27], tiles[32], nullptr, nullptr, nullptr });
tiles[32] = std::make_shared<Tile> (32, 4, TileLink<6>{ tiles[27], tiles[28], tiles[31], tiles[33], nullptr, nullptr });
tiles[33] = std::make_shared<Tile> (33, 3, TileLink<6>{ tiles[28], tiles[29], tiles[32], nullptr, nullptr, nullptr });
}
std::array я передаю конструктору Tile не меняется. Как бы мне заставить его измениться?
Любая помощь будет принята с благодарностью. Извините за такой длинный вопрос, я действительно не знал, как сделать это меньшим примером.
Вы можете использовать ссылку или указатель на него. Или референсная обертка, например std::ref.
зачем вообще хранить TileLink в shared_ptr? Пока существует доска, плитки существуют, и ссылки должны быть действительными. И если это 2D-доска, а ссылки на плитки — это просто соседи, вы можете просто сохранить их в 2D-сетке.
Указание void в качестве списка параметров Board (void); является C-измом. В C++ используйте Board ();, так как в C++ отсутствие параметров означает «нулевые параметры», тогда как в C отсутствие параметров означает «неизвестное количество параметров».
@Zaiborg спасибо за понимание, доска - это сетка, в которой я храню плитки, но сетка не прямоугольная (она ближе к шестиугольной) и, следовательно, странные соединения.
@Элджей, это не совсем относится к проблеме, которую я демонстрирую. Если у вас есть какие-либо мысли по заданному мною вопросу, пожалуйста, оставьте комментарий. Но просто для того, чтобы нам было ясно, что Board (void) является совершенно допустимым синтаксисом C++ для примера, который я привел, и только потому, что что-то является C-синтаксисом, не означает, что он неправильный или хуже.
Вот почему я оставил это как комментарий, а не ответ.
с шестнадцатеричными досками для этого есть отличный сайт: redblobgames.com/grids/hexagons там также объясняется, как вы можете хранить свои значения в массиве 2d, а также находить пути и соседей





Здесь:
tiles[0] = std::make_shared<Tile> ( 0, 3, TileLink<6>{ tiles[1], tiles[4], tiles[5], nullptr, nullptr, nullptr });
tiles[1], tiles[4] и т. д. еще не инициализированы и имеют shared_ptr значение nullptr. Когда вы инициализируете tiles[1] позже, это не меняет того, что внутри tiles[0].
Вы совершенно неправильно используете shared_ptr. Поскольку ваш массив плиток имеет фиксированный размер, просто выделите один раз всю необходимую память, а затем используйте указатели, не являющиеся владельцами. Потому что есть владелец памяти и это Board.
Я согласен с первой частью ответа. А вот второе не понятно написано. Я думаю, вы имеете в виду следующее: TileArray должно быть std::array<const Tile, N> и TileLink должно быть std::array<Tile const * const, N>, верно? На самом деле это не сработает из-за константности и конструкторов Tile. Но я согласен, что shared_ptr здесь совершенно неуместно. Может быть, больше TileArray как std::array<std::unique_ptr<const Tile>, N> и TileLink как std::array<Tile const * , N>, но проблема в том, что указатели TileLink не являются константами.
Хорошо, так что std::shared_ptr<> в этом сценарии неправильно, и я должен использовать только Tile объекты в массиве в Board с уникальными ссылками на объект в соседнем списке. Но как тогда мне инициализировать список в массиве в конструкторе Board?
Некоторая константность должна уйти. Даже конструктор не может правильно построить объект (это действительно проблема ОП). Удалите константность, используйте один массив для хранения ваших плиток, обновите все ссылки в теле ctor. Затем объявите свою доску как: const Board theBoard; и с точки зрения клиентов все будет константно, если это действительно то, что вы хотите... (но я сомневаюсь в этом)
Я решил свою проблему - спасибо @t.niese и @fjardon за вашу помощь.
Мне пришлось сделать Tile более сложным, чтобы облегчить реальную проблему здесь: я не смог создать уникальный Tile объект из std::array в классе. Поэтому я добавил конструктор копирования и оператор присваивания, удалил умные указатели и const-ность и сделал массив типа класса Tile.
class Tile;
template <const std::size_t N> using TileLink = std::array<const Tile *, N>;
template <const std::size_t N> using TileArray = std::array<Tile, N>;
enum class OWNERSHIP { PLAYER_1, PLAYER_2, CONTESTED };
class Tile {
private:
OWNERSHIP territory;
/* surrounding tiles */
std::size_t ID;
std::size_t num_adj;
TileLink<6> adjacent = { nullptr };
public:
Tile (void) { }
Tile (OWNERSHIP own, std::size_t id, std::size_t num, const TileLink<6> & arr);
Tile (const Tile & rhs);
Tile & operator = (Tile other);
~Tile (void) = default;
};
class Board {
private:
TileArray<34> tiles;
void create_col_1_and_7 (void);
void create_col_2 (void);
...
void create_col_6 (void);
public:
Board (void);
~Board (void) = default;
};
Каждая из инициализаций теперь выглядит так:
tiles[0] = Tile (OWNERSHIP::PLAYER_2, 0, 3, TileLink<6>{ &tiles[1], &tiles[4], &tiles[5], nullptr, nullptr, nullptr });
tiles[1] = Tile (OWNERSHIP::CONTESTED, 1, 4, TileLink<6>{ &tiles[0], &tiles[2], &tiles[5], &tiles[6], nullptr, nullptr });
...
tiles[32] = Tile (OWNERSHIP::CONTESTED, 32, 4, TileLink<6>{ &tiles[27], &tiles[28], &tiles[31], &tiles[33], nullptr, nullptr });
tiles[33] = Tile (OWNERSHIP::PLAYER_1, 33, 3, TileLink<6>{ &tiles[28], &tiles[29], &tiles[32], nullptr, nullptr, nullptr });
Сомневаюсь, что кто-то будет смотреть код. Опубликуйте Макви, который показывает проблему с кодом как можно меньше.