Как динамически выделить 2D std::array в C++ или почему мне не следует его использовать?

Я хочу выделить массив в своем коде, и его размер должен быть определен во время выполнения.

Я пробовал так:

#include <iostream>
#include <array>

int main(){
    int M=4,N=3,P=5;
    M=N+P;
    std::array<std::array<double,M>,N> arr;
}

Но MSVC сказал мне:

a variable with non-static storage duration cannot be used as a non-type argument

Я не нахожу ответа на этот вопрос в stackoverflow. (Существующий вопрос, похоже, не решает мою проблему...)

Как динамически выделить 2D std::array в С++?

Я знаю, что мог бы использовать std::vector, чтобы решить эту проблему. Но размер векторной памяти должен быть организован мной, и это будет использоваться много раз в моем проекте. И я хочу использовать код типа C++, а не тип C... Может быть, есть способ превратить 2D-массив типа C в std::array, но я не могу найти его в Google...

Вот и задаюсь этим вопросом...

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

#include <iostream>

int main(){
    int a=3;
    int b=4;
    int rowCount=a+b;
    int colCout=b-a;
    int** a = new int*[rowCount];
    for(int i = 0; i < rowCount; ++i)
    {
        a[i] = new int[colCount];
    }
}

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

Я думаю, что емкость вектора больше, чем его размер, я хочу этого избежать. Но другой вопрос: Как ограничить емкость std::vector количеством элементов показывает, что я должен использовать свой распределитель или std::vector::shrink_to_fit(), чтобы избежать его... (В С++ 17 нет гарантии, если вы используете reserve(n))

Вам нужен std::vector. std::array имеет фиксированный размер во время компиляции.

drescherjm 10.04.2022 16:31

Если вы хотите использовать код типа C++ вместо кода C для обработки контейнеров, размер которых неизвестен до времени выполнения, вы хотите использовать std::vector. Я не понимаю вопроса.

Nathan Pierson 10.04.2022 16:31

std::vector — правильное решение. "Но объем векторной памяти нужно организовать самому" Я не понимаю, что вы хотите сказать.

HolyBlackCat 10.04.2022 16:31
Я имею в виду, что M и N должны быть получены динамически (не изменены, но я могу знать это только во время выполнения...) Тогда вам понадобится std::vector, а не std::array.
drescherjm 10.04.2022 16:36

Возможно, вам нужно показать, почему вы считаете, что std::vector не подойдет для вашей проблемы. Я думаю, что это немного проблема XY.

drescherjm 10.04.2022 16:42

@drescherjm Поскольку размер векторной памяти больше, чем у того же массива, если я не контролирую сам, я думаю, что должен получить его в конструкторе ...

Learning Lin 10.04.2022 16:43

Возможно, вы хотите выделить одномерный вектор и использовать матричный класс

drescherjm 10.04.2022 16:44

@LearningLin, в этом нет смысла. std::vector даст вам именно ту память, которая вам нужна.

Marcus Müller 10.04.2022 16:44

@drescherjm Я получу vector.capacity() в конструкторе "fine_vector"

Learning Lin 10.04.2022 16:44

@LearningLin что? Это бессмысленно.

Marcus Müller 10.04.2022 16:45

@MarcusMüller Думаю, ты прав. Я имею в виду, что если я не использую push_back, размер памяти должен быть таким, каким я хочу. Спасибо.

Learning Lin 10.04.2022 16:48

есть конструктор std::vector, с помощью которого вы можете указать точный размер, см. (3) в списке в cppreference - (отредактируйте также упоминается в ответе Маркуса Мюллера, который я только что видел)

codeling 10.04.2022 16:51

@drescherjm Да, это проблема XY.

Learning Lin 10.04.2022 17:12
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
0
13
37
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Динамически выделяемый контейнер массива в C++ — это std::vector. std::array предназначен специально для массивов фиксированная длина во время компиляции.

https://cppreference.com твой друг!

But the vector memory size needs to be organized by myself

Не совсем уверен, что вы имеете в виду, но вы указываете размер своего std::vector с помощью конструктора.

std::vector<std::vector<int>> arr(N);

Если вам нужен какой-то специальный распределитель (не только new/malloc), вы также можете указать собственный распределитель.

Вся ваша программа, которую вы предлагаете, не является хорошим C++. Решение C++ будет выглядеть так:

#include <vector>
int main() {
    int a = 3;
    int b = 4;
    unsigned int rowCount = a + b;
    unsigned int colCount = b - a;
    std::vector<std::vector<int>> matrix(rowCount);
    for (auto& row : matrix) {
        row.resize(colCount);
    }
}

Хорошо, я понял. Думаю, мне следует определить для него новый тип.

Learning Lin 10.04.2022 16:40

@LearningLin Я не думаю, что в этом был смысл

Ted Lyngmo 10.04.2022 16:41

...Что? Каков ваш вывод из этого?

Nathan Pierson 10.04.2022 16:41

@LearningLin нет, дело было вовсе не в этом. Вам не нужен новый тип. Существующий std::vector<std::vector<int>> просто работает.

Marcus Müller 10.04.2022 16:42

@MarcusMüller Думаю, ты прав. Я имею в виду, что если я не использую push_back, размер памяти должен быть таким, каким я хочу. Спасибо

Learning Lin 10.04.2022 16:47

Верен ли мой ответ? Я имею в виду, что емкость вектора может быть больше вектора. И я хочу этого избежать. В С++ 17 другой вопрос показывает, что нет метода, если я не использую свой распределитель. Он выходит в С++ 20?

Learning Lin 10.04.2022 17:08

Я не понимаю, о чем ты меня здесь спрашиваешь. Но если что-то существовало в C++17, оно будет существовать и в C++20. Кроме того, вы, кажется, думаете, что избыточное выделение ресурсов — это действительно плохо, но это не так. Если страницы памяти, выделенные для вектора, не затрагиваются, они не используют физическую память. Таким образом, максимум, что вы тратите впустую, может быть чуть меньше 4 КБ в ОЗУ. Которые вы бы тоже потратили впустую с new или malloc, вы просто не замечаете.

Marcus Müller 10.04.2022 17:12

std::array, как и настоящий массив в C++, требует постоянного размера. Это то, что дает ему какое-либо преимущество перед std::vector.

Для технического объяснения того, как реализуется это требование, помните, что параметры шаблона должны быть константами времени компиляции (поскольку это изменяет способ генерации кода, опять же во время компиляции).

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

Хорошо, я понял. Думаю, мне следует определить для него новый тип.

Learning Lin 10.04.2022 16:39

@LearningLin совсем не то, что сказал Блинди. Вы, должно быть, неправильно поняли!

Marcus Müller 10.04.2022 16:43

@MarcusMüller Я знаю, где я неправильно понял, спасибо.

Learning Lin 10.04.2022 16:54

Другие вопросы по теме