Многомерные массивы как член класса с произвольными границами

Не дубликат C++: инициализация многомерного массива в конструкторе, поскольку все ответы < em>кажется, чтобы предположить, что границы известны во время компиляции.

Я создаю класс взвешенного неориентированного графа arraygraph, поддерживаемый двумерным массивом int, по имени edges[][]. Во время создания мне все равно, что содержит edges[][]; arraygraph имеет метод, который считывает график из заданного имени файла, а edges устанавливается в new int[n][n] (где n — количество узлов в файле) этой функцией перед его заполнением.

Проблема в том, что g++ не нравится то, как я определил edges[][]. Он хочет установить границы для массива, а во время компиляции я не знаю этих границ. Должен ли я просто переопределить edges как int *? Или как edges[][0]? Или что-то совсем другое?

Я ни в коем случае не эксперт по С++ (я вроде как парень на Python), такие сложные, тяжеловесные параметры, как те, что в Массив с неопределенным размером в качестве члена класса выходит за рамки (наверняка есть более простой способ, чем этот...). Если то, что я пытаюсь сделать, совершенно неправильно, то это также полезно знать, и было бы удобно знать, что я должен делать вместо этого.


person Schilcote    schedule 27.03.2015    source источник
comment
это отвечает на ваш вопрос? В нем обсуждаются только двумерные массивы, но он применим к любым прямоугольным массивам (т. Е. Массивам, в которых для каждого измерения каждый элемент имеет одинаковый размер).   -  person bames53    schedule 28.03.2015


Ответы (2)


С++ не знает массивов переменной длины. Поэтому вам нужно определить свой массив с постоянным размером. Также невозможно переопределить массив.

Два варианта для вашего многомерного массива:

  • динамический массив массивов, реализованный как int **edges
  • std::vector вместо vector<vector<int>> edges;

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

int N=10; // dynamic! 
vector<vector<int>> m(N, vector<int>(N));

Альтернативой использованию указателя будет:

int N=10; // dynamic! 
int**m = new int*[N];    // allocate the first array 
for (int i = 0; i < N; i++) {  // allocate the second arrays
    m[i] = new int[N]{};
}

В обоих случаях вы получите доступ к данным с одним и тем же синтаксисом:

for (int i = 0; i < N; i++) {
    for (int j = 0; j < N; j++)
        cout << m[i][j] << "\t";
    cout << endl;
}
person Christophe    schedule 27.03.2015
comment
vector<vector<int>> работает, но обычно это не лучшая идея для прямоугольных массивов; он использует больше памяти и выделений, чем необходимо. - person bames53; 28.03.2015
comment
Это шаг в правильном направлении, но есть ли какие-то хитрости в добавлении значений к этим векторам? Он просто создает слот для меня каждый раз, когда я пишу в новый индекс (я буду писать только один раз и делать это от 1 до n, если это имеет значение)? Или я должен сказать ему изменить размер себя, чтобы быть таким большим, прежде чем я напишу ему? - person Schilcote; 28.03.2015
comment
@bames53 Жизнь коротка, DIMM дешевы. :П - person Schilcote; 28.03.2015
comment
О, и было бы удобно знать, что мне нужно #include <vector>, чтобы заполучить vector. - person Schilcote; 28.03.2015
comment
@Schilcote Это не просто использование большего количества памяти; Тот факт, что память не является непрерывной, также означает, что она может быть значительно медленнее. Это также более подвержено ошибкам и менее читабельно, если вам нужны прямоугольные массивы. - person bames53; 28.03.2015
comment
Синтаксис в приведенной выше демонстрации автоматически создает все ваши записи N на N. Позже вы можете изменить размер() каждого вектора по своему усмотрению. Или вы можете просто создать вектор большего размера, как указано выше, и назначить его для перезаписи старого. - person Christophe; 28.03.2015
comment
@bames, если вы используете int**, у вас также нет смежности. - person Christophe; 28.03.2015
comment
@ Кристоф Это правда. Я бы тоже не рекомендовал int**. Вместо этого я бы предложил что-то вроде этих строк. - person bames53; 28.03.2015
comment
@ bames53 да, выравнивание массива также является альтернативой (+1 к связанному ответу). Но вам нужно будет явно использовать это измерение во всех индексациях. И если код уже существует для двух измерений, ОП необходимо будет его переписать. - person Christophe; 28.03.2015
comment
@Christophe Это не совсем тривиально, но можно реализовать класс шаблона многомерной матрицы, который поддерживает произвольное количество измерений, каждое из которых имеет размер во время выполнения, и который использует сглаженный массив для хранения: доказательство концепции. В этой реализации используются некоторые функции C++17, но она работает с текущей версией clang 3.7. - person bames53; 28.03.2015
comment
@bames53 Очень интересная идея! - person Christophe; 28.03.2015

Кажется, вы ищете массив динамического размера. Попробуйте использовать std::vector вместо массива.

person warownia1    schedule 27.03.2015