Сложности в понимание создания трёхмерных динамических структур в С++

Всех приветствую. Есть сложность в понимании задании многомерных динамических структур в C++. Если я правильно понимаю, то задать можно так(возьму в пример 3х мерную структуру):

vector<vector<vector<double>>> vector3d;

или видел такую запись:

using vector3d = vector<vector<vector<double>>>;
const vector3d& SECT;

Но честно говоря я не понимаю чем это отличается от

double ***vector3d;

Так же не понятно, нужно ли и как выделять память для этой ДИНАМИЧЕСКОЙ структуры до заполнения её.


Ответы (2 шт):

Автор решения: Никита Самоуков

double ***vector3d; это указатель. И не факт что на трехмерный массив.

vector<vector<vector>> vector3d; это класс. Класс создан для удобного оперирования массивами. В нем реализованы методы для изменения размера и автоматического удаления памяти. Напрямую выделять память не нужно, но чтобы в нем появились элементы нужно делать ресайз(или иной метод вызвать схожий).

Разница же в методах в том, что ***vector3d это сишный вариант, его в плюсах лучше не использовать. Плюсы все же создавались чтобы вектор как класс создать.

Ещё стоит учесть, что в иногда сишные файлы компилируют как плюсовые, потому что так проще.

→ Ссылка
Автор решения: Swift - Friday Pie

Вектор векторов v - это контейнер, содержащий контейнеры. Каждый контейнер типа vector надо заполнять отдельно, по умолчанию память не выделена. Ну и так как все вектора - независимые структуры, данные в них разбросаны где попало и у них может быть разный размер.

vector<vector<vector<double>>> v = {
  {{0, 1, 2}},        // в 1м слое у нас 1 строка с 3 эл.
  {{3, 4},{1}},       // в 2м слое у нас 2 строки с 2 и 1 эл.
  {{3},{1,2},{4,5,6}},// в 3м слое у нас 3 строки
};

Указатель vector3d типа double *** может быть указателем на массив указателей double **, каждый из которых может является указателем на массив double *, а те - на массивы double. Но это также может быть указатель на первый элемент массива double ***. Выделяется память поочередно для каждого, в цикле. Как и у вектора векторов, все разбросано по памяти и разного размера, вот только сама структура размер не хранит!

Такую структуру иногда называют ragged array ("рваный" массив). В С++ в "голом" виде ее использовать не следует, а стоит описать класс, работающий с ним и хранящий размеры (тем самым выполнив S, O, I из SOLID).

Если же нужен монолитный 3х-мерный массив где все слои, столбцы и строки одинаковы, то лучше уж использовать одномерный массив или вектор. И завернуть все в класс с трехмерным индексом, примерно так (не проверялось):

#include <vector>

class Matrix {
public:
    using DataType = double;

    Matrix(const Matrix&) = default;
    Matrix(Matrix&&) = default;
    Matrix(int a, int b, int c): _a(a), _b(b), _c(c), _el(Matrix::init(a,b,c)){}
    ~Matrix() = default;

    // Оператор индекса. В C++23 можно заменить на оператор
    // operator[](int a, int b, int c)
    DataType& operator()(int a, int b, int c) { return _el[_b*_c*a + _c*b + c]; }
    // возвращает указатель на монолитный массив
    DataType* data() { return _el.data(); }

private:
    using Cont = std::vector<DataType >;

    int _a, _b, _c;
    Cont       _el;

    static Cont init(int a,int b,int c) {
        Cont temp(a*b*c);
        return temp;
    }
};

int main()
{
    Matrix v3d(3,3,3);
    v3d(0,0,0) = 42;   
    v3d(2,2,1) = 34;   
}
→ Ссылка