#c #multidimensional-array #struct #heap-memory #new-operator
Вопрос:
Недавно я начал работать с C для численных вычислений, где я хочу использовать a Struct Operators
для хранения 3D-полей в ходе моделирования. Я создаю 3D-массивы в куче с помощью
const unsigned int RES = 256;
auto arr3D = new double [RES][RES][RES];
потому что, судя по тому, что я протестировал, этот подход быстрее, чем использование Boost_multiarr, собственного тензора или вложенных векторов.
До сих пор это хорошо работало с моим минималистичным Test.cpp но когда я пытаюсь реализовать эти же 3D-массивы в качестве членов my Struct Operators
, я больше не могу использовать auto
команду:
const unsigned int RES = 256;
struct Operators {
public:
std::complex<double>*** wfc; // edited, see 'spitconsumers' comment
Operators(Settings amp;set) { // just another structure used by Operators
wfc = new std::complex<double> [RES][RES][RES];
// ...Initializing wfc using Settings
};
В этом случае я не нашел способа объявить wfc
, чтобы я не получал ошибок типа
ошибка: не удается преобразовать «std::сложный (*)[256][256]’ в «std::комплекс***» в задании
Поэтому мой вопрос заключается в том, как правильно объявить 3D-массив wfc
и возможно ли вообще/полезно поддерживать такой подход к структуре. Было бы вообще быстрее получить доступ к wfc[i][j][k]
if wfc
, если бы он не был членом структуры? (Мне придется сделать это ~10^6 раз)
Заранее спасибо!
Комментарии:
1. Я бы пропустил
[][][]
синтаксис и просто использовал один вектор. Элемент[z*RES*RES y*RES x]
даст вам эквивалент[z][y][x]
.
Ответ №1:
Сообщение об ошибке возвращает правильное объявление, std::complex<double>(*wfc)[RES][RES];
.
const unsigned int RES = 256;
struct Settings {};
struct Operators {
public:
std::complex<double>(*wfc)[RES][RES]; // edited, see 'spitconsumers' comment
Operators(Settingsamp; set) { // just another structure used by Operators
wfc = new std::complex<double>[RES][RES][RES];
// ...Initializing wfc using Settings
// Setting the last element
wfc[254][254[254] = 42;
};
}
Комментарии:
1. Спасибо за решение, это было именно то, что я искал! Однако я нахожу, что решение splitconsumer в два раза быстрее, когда я измеряю время, необходимое для выполнения операций над формой
T[ix][iy][iz] = std::pow(P[ix][iy][iz], 2) - n_L;
с циклами for для каждогоi,j,k
. Связано ли это с выделением памяти?2. @Azure27 Звучит так, как будто скомпилированный код вычисляет каждое местоположение при каждом доступе, что было бы довольно медленным, поскольку для получения смещения требуется два умножения и 3 добавления. Это было бы плохой производительностью оптимизатора. Убедитесь, что вы используете-O3 Для других проблем, связанных с перекрестным доступом, таких как умножение массивов, подход к массиву указателей обычно медленнее, поскольку математика процессоров в регистрах ЦП выполняется быстрее, чем доступ к указателям.
Ответ №2:
В вашем сообщении об ошибке компилятор сообщает вам, что new complex [RES][RES][RES]
возвращает тип std::complex (*)[256][256]
.
double wfc
должно быть std::complex*** wfc
.
Типы членов класса должны быть известны, и, поскольку вы не инициализируете переменную-член во время ее определения, компилятор не может определить тип переменной, поэтому auto
она не работает как тип члена класса, когда вы не назначаете ей что-то немедленно. Но вы присваиваете значение непосредственно переменной в своей тестовой программе, позволяя компилятору вывести тип там.
Кроме того, new
оператор возвращает указатель на массив неинициализированных std::complex<double>**
указателей. Вам нужно вызвать new
все неинициализированные указатели.
std::complex<double>*** wfc;
wfc = new std::complex<double>** [RES];
for(int i = 0; i < RES; i ) {
wfc[i] = new std::complex<double>* [RES];
for(int j = 0; j < RES; j ) {
wfc[i][j] = new std::complex<double> [RES];
for(int k = 0; k < RES; k ) {
wfc[i][j][k] = /* insert default value here */;
}
}
}
Комментарии:
1. Спасибо, в этом есть большой смысл! Замена
double
сstd::complex<double>***
, я теперь получаю ошибку > ошибка: невозможно преобразовать ‘комплекс ( )[256][256]’ {ака ‘станд::комплекс<double> ( )[256][256]’} в комплексе***’ {ака ‘станд::комплекс<double>***’} в назначении ВЛК = новый комплекс [ресурс][ресурс][рез];2.
new
оператор возвращает указатель на массив неинициализированных указателей. Вам нужно запустить поисковый запрос, вызывающийnew
все неинициализированные указатели. Я отредактирую свой ответ, чтобы ваша проблема была полностью решена (надеюсь).3. для цикла*. Досадная опечатка.
4. Большое спасибо, этот подход отлично работает! Хотя это не так коротко, как решение Дугса,я нахожу в своих тестах производительности,что оно в два раза быстрее в отношении операций с элементами, таких как
T[ix][iy][iz] = std::pow(P[ix][iy][iz], 2) - n_L;
для каждого i, j, k. Связано ли это с тем, как выделяется память?