Доступ к члену всех структур в массиве

У меня есть структура Foo;

typedef struct {

    int bar;
    char baz;

} Foo;

Предположим, я объявляю массив Foo как;

Foo* arr = new Foo[300];

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

int* barr_arr = ...

Как это сделать наиболее эффективно? Есть ли способ использовать структуру памяти, чтобы мне не нужно было перебирать весь массив Foo?

Поскольку мы заранее знаем структуру памяти, можем ли мы использовать тот факт, что мы знаем адрес каждого члена, если мы умно подходим к выравниванию?

Я очень хотел бы иметь возможность получить массив всех панелей участников; Почему? Какую реальную проблему вы пытаетесь решить?
R Sahu 07.06.2018 18:49

Вы не можете получить простой int* из вашего Foo*, потому что между целыми числами есть строки (так что обычная арифметика указателя уже приведет к неопределенному поведению). В C++ можно создавать итераторы, представляющие целые числа в этом диапазоне, которые затем можно использовать со всеми функциями STL. Между прочим, вы должны выбрать между C и C++ в ваших тегах.

Max Langhof 07.06.2018 18:50

@RSahu У меня есть данные, в которых иногда мне нужно посмотреть на всю полосу, базу и т. д. Одного элемента, а в других случаях мне нужно посмотреть на всю базу, но на панель мне наплевать. Например, скажем, у меня есть сетка глубин земли, воздуха и неба. Иногда мне нужно знать глубину каждого в данной ячейке, иногда мне нужно знать глубину земли в каждой ячейке.

user1151695 07.06.2018 18:52

@MaxLanghof Я удалил строку из примера - мои типы данных в основном числовые, и уловки из C вполне применимы.

user1151695 07.06.2018 18:52

Извините, но это все еще не C. Вам нужно решить, какой язык вы используете, поскольку ответы также могут отличаться. Они не одинаковы!

sidyll 07.06.2018 18:53

Неважно, что у вас есть между ними. Указательная арифметика вас просто подведет.

Max Langhof 07.06.2018 18:53

Если вы используете new в своем фактическом коде, C++ - правильный тег. @Sidyll пытается подчеркнуть, что, хотя вы можете написать C++, который почти полностью похож на код C, существуют значительные различия в стандартизированном поведении и компиляторах, которые очень важны, особенно для такого вопроса.

Linuxios 07.06.2018 18:55

Это недостаточная причина для создания int*, указывающего на массив, содержащий все элементы barFoo. Вы можете передать ссылки на Foo и вытащить член bar. Я не думаю, что это такая уж большая проблема.

R Sahu 07.06.2018 18:55

@sidyll, извините, вы правы, ключевое слово new делает это только C++. Удален тег.

user1151695 07.06.2018 18:55

@RSahu: Зависит. Если ему нужно передать массив bar в какой-то другой API, он должен каким-то образом его сконструировать.

Linuxios 07.06.2018 18:56

@RSahu конкретным примером может быть то, что я хочу отправить непрерывный массив полос на графический процессор для параллельной обработки

user1151695 07.06.2018 18:57

@Linuxios есть.

user1151695 07.06.2018 18:57
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
12
149
5

Ответы 5

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

struct FooArray {
  int* bars;
  char* bazes;
  size_t n_elements;
};

Это устраняет необходимость выделять новый буфер для массива bar, что, в зависимости от того, сколько Foo обрабатывается, может привести к значительной экономии памяти.

Я также хотел бы отметить, что, если вы не работаете на низком уровне и на самом деле не нуждаетесь в int*, но можете обойтись с std::vector<int>, то ответ @R Sahu, вероятно, будет более подходящим решением.

Я рассматривал это решение, но иногда мне нужен быстрый доступ, например. Foo [3] и все его члены. Полагаю, мне было бы лучше узнать, в каких из них мой код тратит больше времени, и оптимизировать в этом направлении.

user1151695 07.06.2018 19:09

@ user1151695: Я не думаю, что индексация нескольких целочисленных массивов "медленная" ... вы всегда можете написать удобную функцию, которая сделает это за вас. С другой стороны, распределение ...

Linuxios 07.06.2018 19:10

@ user1151695: Но да. Сначала профилируйте, потом оптимизируйте :).

Linuxios 07.06.2018 19:11

What is the most efficient way to do this? Is there some way to exploit the memory layout such that I need not loop over the entire Foo array?

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

Кроме того, я бы рекомендовал использовать std::vector вместо выделения массива с помощью new.

std::vector<Foo> arr(300);

....


std::vector<int> bArr(arr.size());
std::transform(arr.begin(), arr.end(), bArr.begin(), [] -> (Foo const& f) { return f.bar; });

Цель движет дизайном.

Если ваше основное использование - передача всех членов bar в строке, то же самое для членов baz, затем создайте отдельные контейнеры:

std::vector<int> bar;
std::vector<char> baz;

Тогда передать bar как массив очень просто: просто используйте bar.data().

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

struct Foo
{
    int bar;
    float baz;
};

const int SIZE = 5;
Foo foos[SIZE];
int *bars[SIZE];
for(int c = 0; c < SIZE; c++) {
    foos[c].bar = c;
    foos[c].baz = c;
    bars[c] = &foos[c].bar; // Grab pointer to field
}

for(int c = 0; c < SIZE; c++) {
    std::cout << "Bar Value: " << *bars[c] << std::endl;
}

Если вы добавите к вашему Foo конструктор, который принимает размер массива, у вас может быть только один объект Foo. Затем вы можете сделать так, чтобы вы могли получить доступ либо ко всем векторным данным, либо к отдельным элементам с нижним индексом:

#include <iostream>
#include <vector>
#include <memory>

struct Foo
{
    std::vector<int> bars;
    std::vector<char> bazs;
    std::size_t size;

    Foo(size_t size, int bar = 0, char baz = 0) :
        bars(size, bar), bazs(size, baz), size{size}
    {
    }

    auto operator[](size_t n)
    {
        // if (n >= size) ...
        struct
        {
            int &bar;
            char &baz;
        } temp{ bars[n], bazs[n] };
        return temp;
    }
};


int main()
{
    Foo arr(30, 100, 'a'); // 30 items

    std::cout << arr[29].bar << std::endl;
    std::cout << arr[29].baz << std::endl;

    std::cout << arr.bars[29] << std::endl;
    std::cout << arr.bazs[29] << std::endl;

    std::unique_ptr<Foo> arr2 = std::make_unique<Foo>(25, 10, 'b'); // 25 items

    std::cout << arr2->operator[](15).bar << std::endl;
    std::cout << arr2->operator[](15).baz << std::endl;

    arr2->bars[15] = 11;
    std::cout << arr2->bars[15] << std::endl;
    arr2->bazs[15] = 'c';
    std::cout << arr2->bazs[15] << std::endl;

    return 0;
}

Демо: https://ideone.com/TiVwOT

100
a
100
a
10
b
11
c

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

Nemo 06.07.2018 20:09

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