Инициализация динамического массива

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

Добрый день, камрады. Подскажите, есть ли какой то способ инициализировать динамически

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Ты бы хоть код привёл. Что за массив?

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

Черт, рука дрогнула. Начну сначала:

Добрый день, камрады. Подскажите, есть ли какой то способ инициализировать динамический массив при создании:

Есть такой класс: 

class TsButton {

public:
  TsButton()
    : _posX(0), _posY(0), _style(SIZE_3_FULL), _namesIndex(0){};

  TsButton(const uint16_t posX, const uint16_t posY, const Style style, uint8_t index)
    : _posX(posX), _posY(posY), _style(style), _namesIndex(index){};

  friend bool operator==(const TsButton &button, const TS_Point &point);

  int16_t _posX;
  int16_t _posY;
  Style _style;
  uint8_t _namesIndex;
};

Нужен массив классов, создаю и инициализирую так:

uint8_t menuButtonsNumber = 3;
const uint8_t verticalGap = (DISPLAY_HEIGHT - (menuButtonsNumber + 1) * 10) / menuButtonsNumber;
TsButton* tsButton_ptr = new TsButton[menuButtonsNumber];

    for (uint8_t buttonNumber = 0; buttonNumber < menuButtonsNumber; buttonNumber++) {
      tsButton_ptr[buttonNumber]._posX = 10;
      tsButton_ptr[buttonNumber]._posY = 10 + (10 + verticalGap) * buttonNumber;
      tsButton_ptr[buttonNumber]._style = pgm_read_byte(&menu[menuFirstLine + buttonNumber].style);
      tsButton_ptr[buttonNumber]._namesIndex = menuFirstLine + buttonNumber;
    }

Очень хотелось бы сделать члены массива константными, но не соображу способ инициализации массива при создании. Буду признателен если подкинете идею как это сделать.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Не, нифига я вопрос не понял.

 

rkit
Offline
Зарегистрирован: 23.11.2016

Сделать члены массива классами с нетривиальным конструктором.

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

вроде в строках 7-8 он и определен. не соображу как его вызвать (аргументы генерируются в цикле).

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Либо добавить конструктор, либо, если религия не позволяет, объявить наследника и у него добавить нужный конструктор.

PS. А вообще класс с публичными полями это IMHO нонсенс.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Это продвинутая структура ))))

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

andriano пишет:

Либо добавить конструктор, либо, если религия не позволяет, объявить наследника и у него добавить нужный конструктор.

PS. А вообще класс с публичными полями это IMHO нонсенс.

Городить геттеры/сеттеры смысла не вижу, слишком все тривиально, но хотелось бы закрыть члены от изменения. Параметрический конструктор есть (строки 7-8), по одному инициализировать классы при создании получается, затем объявить и инициализировать ими массив тоже получается.

А как массив создать и инициализировать анонимными объектами класса - не могу сообразить.

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Тогда я тоже не понял, что Вам надо.

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

Один экземпляр я могу объявить и инициализировать так: 

TsButton* tsButton2_ptr = new TsButton{ 10, 20, SIZE_3_FULL, 4 };

А хотелось бы аналогичным образом объявить и инициализировать массив:

TsButton* tsButton2_ptr = new TsButton[2]{ 10, 20, SIZE_3_FULL, 4, 10, 20, SIZE_3_FULL, 4 };

Но никак. Хотя опой чувствую что как то можно.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Напиши отдельный метод, что мешает то?)))

TsButton[2].Init (10, 20, SIZE_3_FULL, 4 );

 

rkit
Offline
Зарегистрирован: 23.11.2016

Dinosaur пишет:

вроде в строках 7-8 он и определен. не соображу как его вызвать (аргументы генерируются в цикле).

Там определен конструктор класса, а в массиве у тебя указатели.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

А вот так можно, интересно?

class TsButton {

public:
  TsButton()
    : _posX(0), _posY(0), _style(SIZE_3_FULL), _namesIndex(0){};

  TsButton(const uint16_t posX, const uint16_t posY, const Style style, uint8_t index)
    : _posX(posX), _posY(posY), _style(style), _namesIndex(index){};

  friend bool operator==(const TsButton &button, const TS_Point &point);

  const int16_t _posX = 10;
  const int16_t _posY = 20;
  const Style _style = SIZE_3_FULL;
  const uint8_t _namesIndex = 4;
};

 

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

BOOM пишет:

Напиши отдельный метод, что мешает то?)))

TsButton[2].Init (10, 20, SIZE_3_FULL, 4 );

Так константными хочу сделать члены. Какой тут init :(

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

BOOM пишет:

А вот так можно, интересно?

Можно, но зачем? Задача прийти к:

class TsButton {

public:
  TsButton(const uint16_t posX, const uint16_t posY, const Style style, uint8_t index)
    : _posX(posX), _posY(posY), _style(style), _namesIndex(index){};

   const int16_t _posX;
   const int16_t _posY;
   const Style _style;
   const uint8_t _namesIndex;
};

 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

#13 глянь. И конструктор вообще не нужен тогда, пустым остаётся.

И вообще это все на обычную структуру похоже получается. ))

struct  TsButton {

  const int16_t _posX = 10;
  const int16_t _posY = 20;
  const Style _style = SIZE_3_FULL;
  const uint8_t _namesIndex = 4;
};

А тогда я не понимаю зачем массив структур одних и тех же значений...

b707
Offline
Зарегистрирован: 26.05.2017

Dinosaur пишет:

А хотелось бы аналогичным образом объявить и инициализировать массив:

TsButton* tsButton2_ptr = new TsButton[2]{ 10, 20, SIZE_3_FULL, 4, 10, 20, SIZE_3_FULL, 4 };

а так?

TsButton* tsButton2_ptr = new TsButton[2]  {
     { 10, 20, SIZE_3_FULL, 4},
     { 10, 20, SIZE_3_FULL, 4 }};

 

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

b707 пишет:

а так?

TsButton* tsButton2_ptr = new TsButton[2]  {
     { 10, 20, SIZE_3_FULL, 4},
     { 10, 20, SIZE_3_FULL, 4 }};

Так - вполне, спасибо. Но блин размер массива заранее неизвестен, цикл я так понимаю никак не запихать внутрь фигурных скобок для инициализации?

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

BOOM пишет:

А тогда я не понимаю зачем массив структур одних и тех же значений...

Так они разные (просто поленился писать другие значения и скопировал два раза одни и те же данные)

b707
Offline
Зарегистрирован: 26.05.2017

Dinosaur пишет:

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

тогда вы пошли неверным путем.

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

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

b707 пишет:

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

Тут опять торможу. А разве массивы ссылок бывают? Ссылку понимаю как объявить:

int a;
int &ref = a;

А как массив?

b707
Offline
Зарегистрирован: 26.05.2017

Dinosaur пишет:

Тут опять торможу. А разве массивы ссылок бывают?

конечно

Только тут я неверно выразился, вам нужен не массив ссылок, а массив указателей.

И. кстати, тип переменной tsButton2_ptr в моем примере из сообщения #17 будет не TsButton* , а TsButton**

b707
Offline
Зарегистрирован: 26.05.2017

как-то так

TsButton* button_array[ARRAY_SIZE];

for (int i =0; i<ARRAY_SIZE; i++) {
  //генерируем парметры инициализации
  int16_t  X = 10;
  int16_t  Y = 20;
  Style  style = SIZE_3_FULL;
  uint8_t  index = 4;


  button_array[i] = new TsButton{ X, Y, style, index };
}

 

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

Спасибо, именно это и пытался сообразить. Меня смутил "массив ссылок", и пропустил "массив указателей на указатели". В таком виде работает как мне нужно:

    TsButton** tsButton_ptr = new TsButton*[menuButtonsNumber];
    for (uint8_t buttonNumber = 0; buttonNumber < menuButtonsNumber; buttonNumber++) {
      int16_t posX = 10;
      int16_t posY = 10 + (10 + verticalGap) * buttonNumber;
      Style style = pgm_read_byte(&menu[menuFirstLine + buttonNumber].style);
      uint8_t namesIndex = menuFirstLine + buttonNumber;
      tsButton_ptr[buttonNumber] = new TsButton{ posX, posY, style, namesIndex };
    }

 

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

В догонку вопрос по очистке памяти - так нормально будет?

  for (uint8_t buttonNumber = 0; buttonNumber < menuButtonsNumber; buttonNumber++) {
    delete[] tsButton_ptr[buttonNumber];
  }
  delete[] tsButton_ptr;
  tsButton_ptr = nullptr;

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

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

Я предпочитаю удалять в порядке обратном выделению.

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

andriano пишет:
Я предпочитаю удалять в порядке обратном выделению.

Да, спасибо за замечание, переделал.

void deleteButtonsArray() {

for (int index = (menuButtonsNumber - 1); index >= 0; index--) {
    delete[] tsButton_ptr[index];
  }
  delete[] tsButton_ptr;
  tsButton_ptr = nullptr;
}

andriano пишет:
Зависит от того, насколько "умный" менеджер памяти.

Тут "программист" дурак на всю голову, а вы про умный менедрер памяти. :)

Можете поподробнее раскрыть этот момент (ссылку где почитать либо кусок кода)? В поиске натыкаюсь в основном на: (почти)никода нельзя использовать new и delete, используйте vector, контейнеры и ты ды.

Вопрос кстати про delete и delete[] (код в этом сообщении) - мне кажется что в цикле нужно использовать delete (ведь удаляем не массивы, а элементы массива), а за циклом delete[] для удаления массива. Но в учебнике  в примере (ravesli) используется delete[] как в цикле, так и вне цикла, что меня ставит в тупик. Компилятор принимает оба варианта. Подскажите как правильно освободить память в данном случае.

Ну и  в догонку вопрос - а можно обойтись для рашения этой задачи без использования динамической памяти? В голову приходит сходу объявление глобального массива tsButton максимально возможного размера в стеке, и наполнение его требуемыми по ходу выполнения программы данными, но не хочется (жаба давит) чтобы постоянно была занятой память (tsButton * 10). Хотя опять же для микроконтроллеров читал что следуют всячески избегать использования динамической памяти. 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Я, конечно же, не настоящий самурай ))) Но что-то мне подсказывает, что вместо подобного массива удобнее использовать одно/двух-связанный список (если речь про динамически изменяемый размер). Но может быть опять не понял что ТС хочет.

b707
Offline
Зарегистрирован: 26.05.2017

Dinosaur пишет:

Ну и  в догонку вопрос - а можно обойтись для рашения этой задачи без использования динамической памяти?

А вы поподробнее опишите "эту задачу". Я так понял, динамический массив - для элементов меню? Вы его многократно создаете и уничтожаете  в ходе работы программы?

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

b707 пишет:

А вы поподробнее опишите "эту задачу". Я так понял, динамический массив - для элементов меню? Вы его многократно создаете и уничтожаете  в ходе работы программы?

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

Делаю обектами, чтобы после получения координат точки нажатой на тачскрике, пробегать по массиву обектов и через перегруженный оператор== проверять равенство полученной точки нажатия и кнопки, соответственно обрабатывать нажатие. Ну и опять же изучаю главу ООП, срочно хочется куда-то применить полученные знания :)

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Ну это и есть список, так то...

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

попробуй так

https://arduino.ru/forum/otvlechennye-temy/kudryavaya-initsializatsiya-s...

шаблоном будет указатель на класс, в скобках - конструкторы new()

Gromozeka
Offline
Зарегистрирован: 06.10.2022

Создай массив указателей без new. 

В цикле для каждого элемента отдельно вызывай new c входными параметрами конструктора поиндексно. Передавай нужные параметры при каждом индексе. 

kakaxi
Offline
Зарегистрирован: 20.07.2021

Если нужно только инициализировать, то встроение в цикл не работает?