Использование массива ptr-to-ptr?

Какая польза и объяснение чего-то подобного?

int capacity;
int** number;
this->number = new int*[this->capacity];

Я готовлюсь к экзамену, и на тестовом экзамене они предъявляют требование использования объекта указателя на указатель и создания из него динамического массива. Есть два класса; Бумажник & WalletKeeper.
В решениях они сделали это в заголовочном файле WalletKeeper:

private:
Wallet** wallets;
int capacity;
int size;
/*other stuff below this*/

И в конструкторе:

WalletKeeper::WalletKeeper(int capacity)
{
this->capacity = capacity;
this->size = 0;
this->wallets = new Wallet*[this->capacity];
this->initiate();
}

Я понимаю базовый динамический массив, как это:

Wallet * wallets = new Wallet[capacity];

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

Бумажник не имеет собственного массива, я бы понял это иначе, потому что я прочитал это: Правильный способ инициализации динамического указателя на многомерный массив?

Профессора в отпуске до дальнейших церемоний.

1

Решение

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

Wallet ** w_ptr_ptr = new Wallet*[capacity];
for(int i = 0; i < capacity; i++) {
w_ptr_ptr[i] = new Wallet[i+1];
}

for(int i = 0; i < capacity; i++) {
for(int j = 0; j < i+1; j++) {
w_ptr_ptr[i][j] = Wallet(/*...*/);
}
}

Обратите внимание, что в этом коде w_ptr_ptr[0] имеет массив другого размера, чем w_ptr_ptr[1],

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

std::vector<std::vector<Wallet>> wallets;

for(int i = 0; i < capacity; i++) {
wallets.emplace_back(i+1); //Will automatically create a i+1-sized array.
}

for(int i = 0; i < wallets.size(); i++) { //Note I'm able to query the size here!
for(int j = 0; j < wallets[i].size(); j++) { //Again I can query the size!
wallets[i][j] = Wallet(/*...*/);
}
}
1

Другие решения

Есть много применений массивов указателей.

  1. Изменение порядка. Предположим, вы хотите изменить порядок объектов в массиве. Работа с указателями намного быстрее, чем перемещение всего объекта.
  2. Динамическое распределение. Вы можете удалить или выделить каждый объект в отдельности.
  3. Перераспределение и производительность. Предположим, вы хотите увеличить размер массива. Перераспределение реальных объектов может привести к различным типам проблем (аннулирование). Перераспределение массива указателей, однако, более или менее беспроблемно, а также намного быстрее.
3

Указатель на указатели-объекты обычно используется для матрицы реализация. Действительно, как указатели на объекты реализуют динамический массив, как вы предложили в своем вопросе:

Wallet* wallets = new Wallet[capacity];

заставляет кошельки указывать первое местоположение массива на num -acity Wallet объект.

[Wallet-obj] [Wallet-obj] [Wallet-obj] ... [Wallet-obj]
0           1             2           capacity - 1

Указатель указателей, таких как:

Wallet** wallets = new Wallet*[capacity];

Создать массив Указатель кошелька:

[Wallet-pointer] [Wallet-pointer] [Wallet-pointer] ... [Wallet-pointer]
0              1                 2                capacity-1

Каждый указатель в векторе должен указывать на динамический массив.

Я постараюсь «нарисовать» представление:

 [0][wallet-pointer]  ----> [0][wallet obj] [1][wallet obj] ... [capacity-1][wallet obj]
[1][wallet-pointer]  ----> [0][wallet obj] [1][wallet obj] ... [capacity-1][wallet obj]
...
[capacity-1][wallet-pointer]  ----> [0][wallet obj] [1][wallet obj] ... [capacity-1][wallet obj]

Поэтому для доступа к объекту вы должны использовать что-то вроде:

wallets[0][2];

Это означает доступ к 1-му указателю в массиве указателей с использованием 1-й «строки» объекта для доступа к 3-му объекту этой строки.

Таким образом, как вы можете изобразить, у вас есть матрица, потому что у вас есть динамический массив с n-емкостью, такой как строки с n-емкостью.

Когда вы создаете массив указателей, вы должны инициализировать каждый из них.
Это полный код:

Wallet** wallets = new Wallet*[capacity];

// Now for each pointer you have to allocate a dynamic array of n-elements.
for (size_t i = 0; i < capacity; ++i) {
wallets[i] = new Wallet[capacity];
}

И то же самое для фазы освобождения:

// First of all, deallocate each object in each dynamic array:
for (size_t i = 0; i < capacity; ++i) {
delete[] wallets[i];  // wallets[i] is a dynamic array to deallocate
}

// Finally deallocate the dynamic array of poiter
delete[] wallets;
0
По вопросам рекламы [email protected]