Я почти уверен, что упускаю из виду, но, как писал Swordfish в своем комментарии, std::vector
, содержащий std::vector
s, должен добиться цели.
Если вы хотите двумерный массив с ширинойи ограничение высоты, которое динамически увеличивается, попробуйте следующий код:
template<class T>
class DynamicArray
{
public:
DynamicArray()
: rowCount(0),
colCount(0)
{}
DynamicArray(size_t rowCount_, size_t colCount_)
: rowCount(rowCount_),
colCount(colCount_)
{}
const T& operator()(size_t row, size_t col) const
{
if (row >= rowCount || col >= colCount)
throw std::out_of_range("Row or column index out of range in " __FUNCTION__);
static const T empty;
if (data.size() <= row)
return empty;
const auto& rowData = data[row];
if (rowData.size() <= col)
return empty;
return rowData[col];
}
T& operator()(size_t row, size_t col)
{
if (row >= rowCount || col >= colCount)
throw std::out_of_range("Row or column index out of range in " __FUNCTION__);
if (data.size() <= row)
data.resize(row + 1);
auto& rowData = data[row];
if (rowData.size() <= col)
rowData.resize(col + 1);
return rowData[col];
}
public:
std::vector<std::vector<T>> data;
size_t rowCount, colCount;
};
Массив всегда начинается без каких-либо строк или столбцов, но с ограничением строки / столбца (в конструкторе по умолчанию установлено значение 0).
Оба оператора () в основном делают одно и то же: проверяют индекс строки и столбца и возвращают соответствующую ячейку.Однако, в то время как неконстантный оператор () изменяет размер зубчатого массива для хранения данного элемента, const оператор () просто возвращает ссылку на пустой (созданный по умолчанию) элемент.Таким образом, вы не будете без необходимости создавать все недостающие элементы при итерации по массиву.
Возможно, unordered_map с парой координат в качестве индекса даст вам еще лучшие результаты в зависимости от варианта использования.Вы можете объявить это с помощью std::unordered_map<std::pair<int, int>, T>
.Пара целых чисел должна привести к довольно быстрой функции хеширования.С очень разреженным массивом это было бы моим предпочтительным решением.
Помните, что использование __FUNCTION__
может потребоваться изменить (или опустить), если вы не используете Visual Studio.(в gcc __FUNCTION__
расширяется до функции, которая возвращает имя функции, в то время как Visual Studio расширяет его до строки, содержащей имя текущей функции).