правильное распределение памяти для двумерного массива в классе в C ++ - PullRequest
1 голос
/ 18 февраля 2011

Я пишу класс C ++, который использует некоторые фиксированные массивы, а также некоторые динамически размещаемые массивы.Мне было интересно, может ли кто-нибудь подсказать мне, как правильно распределить память для динамических массивов, возможно, в конструкторе / деконструкторе, а также нужно ли мне явно вызывать их, чтобы убедиться, что я не получаю ошибку сегмента.Вот упрощенная версия связанной части моего кода:

class Network {

    public:
    int n_nodes;
    int user_index[MAX_USERS]; //a fixed array
    int adjacency_matrix[][MAX_ITEMS];

    //Network(int n_node, int** adjacency); //I would rather to set the element s in a function other than the constructor
    Initializer(int n_node, int** adjacency);
    ~Netowrk();
    }

Итак, вот мой конкретный вопрос для этого класса:

1 - Могу ли я иметь двумерный массив adjacency_matrix [] [] с неопределенным числом строк и столбцов до тех пор, пока он не будет установлен пользователем в функции инициализатора?

2 - где я должен удалить двумерный массив?я должен написать это в деконструкторе?Должен ли я вызывать деконструктор явно?Есть ли что-то еще, что мне нужно уничтожить в деконструкторе?

Ответы [ 4 ]

2 голосов
/ 18 февраля 2011

1 - Могу ли я иметь двумерный массив adjacency_matrix[][] с неопределенным числом строк и столбцов, пока он не будет установлен пользователем в функции инициализатора?

Да.Однако лучший способ сделать это - вообще не использовать массивы.Вместо этого используйте std::vector, который управляет памятью для вас.Есть два способа сделать это.Если вы действительно хотите иметь возможность использовать синтаксис [row][column] для доступа к элементам, вам нужно использовать два измерения std::vector s:

std::vector<std::vector<int> > adjacency_matrix;

Как только вы знаете размеры, вы можете заполнитьit:

adjacency_matrix.assign(rows, std::vector<int>(columns));

Часто проще использовать одномерный массив (или std::vector<int>), содержащий все элементы, и использовать row * row_count + column для доступа к элементу по индексу (row, column).Таким образом, меньше динамических распределений.Вы можете заключить логику доступа к элементам в пару вспомогательных функций.

2 - где я должен удалить двумерный массив?я должен написать это в деконструкторе?

Вам не нужно delete ничего, если вы используете std::vector.Он очищается.

Должен ли я вызвать [деструктор] явно?

Нет.

Есть ли что-нибудь еще, что мне нужноуничтожить в [деструкторе]?

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

0 голосов
/ 18 февраля 2011

Есть несколько способов сделать это.

Самый простой способ - использовать векторы, и если вам не нравится управлять собственной памятью, это идеально для вас.Однако, поскольку мне нравится управлять своей собственной памятью, и я иногда нахожу этот метод медленным и громоздким, я узнал о других способах.

Самый быстрый способ - это выделить одномерный массив и обработать его.это как бы двумерный массив.Вот пример:

int *array = new int[width*height];

int get_array(int column, int row)
{
     return array[row*width + column];
}

delete [] array;

Это можно обобщить до n-го измерения:

int *array = new int[w1*w2*...*wn];

int get_array(int i1, int i2, ..., int in)
{
     return array[in*(w1*w2*...*w(n-1)) + i(n-1)*(w1*w2*...*w(n-2)) + ... + i2*w1 + i1];
}

delete [] array;

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

int **array = new int*[height];

for (int i = 0; i < height; i++)
     array[i] = new int[width(i)];

, в какой момент, чтобы получить к нему доступ, все, что вам нужно сделать, - это, как правило,

array[i][j]

, чтобыОсвободив этот массив, вы должны сделать это построчно

for (int i = 0; i < height; i++)
     delete [] array[i];

delete [] array;

Это также может распространиться на n-е измерение.

int **....*array = new int**...*[w1];

for (int i1 = 0; i1 < w1; i1++)
{
     array[i1] = new int**..*[w2];
     for (int i2 = 0; i2 < w2; i2++)
     {
          array[i1][i2] = new int**.*[w3];
          ...
          for (int in = 0; in < wn; in++)
               array[i1][i2]...[in] = new int[wn];
     }
}

for (int i1 = 0; i1 < w1; i1++)
{
     for (int i2 = 0; i2 < w2; i2++)
     {
          ...
          for (int in = 0; in < wn; in++)
               delete [] array[i1][i2]...[in];
          ...
          delete [] array[i1][i2];
     }
     delete [] array[i1];
}

delete [] array;

Этот тип установки имеет тенденцию разрушать память.Только двумерный массив из них привел бы к неправильному выделению ширины + 1 отдельных массивов.Было бы быстрее просто распределить один большой массив и вычислить индексы самостоятельно.

0 голосов
/ 18 февраля 2011

Вам может понравиться пример класса матрицы, который я написал в ответ на другой вопрос

Сам вопрос касался хороших методов проектирования на C ++, но выбранный пример представлял собой многомерный массив.

0 голосов
/ 18 февраля 2011

1 - Могу ли я иметь двумерный массив adjacency_matrix [] [] с неопределенным числом строк и столбцов, пока он не будет установлен пользователем в функции инициализатора?

Да, вы можете .Например:

    int* adjacency_matrix_;
    int* getAdjacency(int i, int j) 
    {
        if (!adjacency_matrix_)
            return 0;
        else 
            return adjacency_matrix_ + i*n_nodes + j;
    }
    Network()
        : n_nodes(0),
        adjacency_matrix_(0)
    {}
    void Initializer(int n_node, int** adjacency)
    {
        adjacency_matrix_ = new int[n_nodes * n_nodes];
        // Copy over data.
    }

Относительно того, должен ли , это зависит от того, есть ли у вас причина не использовать std::vector<>.

2 - где я долженудалить массив 2D?я должен написать это в деконструкторе?Должен ли я вызывать деконструктор явно?Есть ли что-то еще, что мне нужно уничтожить в деконструкторе?

Да, определенно бесплатно в деструкторе, используя оператор массива delete:

~Network()
    {
        delete [] adjacency_matrix_;
    }

Нет, ваш деструктор будет вызываться всякий раз, когда объект Networkсам выходит за рамки.(Очень) редко нужно делать явный вызов деструктора.

Нет, все, что деструктор должен явно освободить, это то, что вы явно приобрели.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...