Массив в конструкторе

#c #oop

#c #ооп

Вопрос:

Что происходит в следующем коде?

Я предполагаю, что это не работает, поскольку я получаю ошибку сегментации, если я хочу добавить что-то в массив b, но что именно я здесь сделал?

Нет ли способа указать размер массива внутри конструктора?

 class A {
  public:
   A() {
      b[3];
   }
  private:
    B b[];
};
  

Комментарии:

1. Что пытается сделать этот код?

2. Я немного удивлен, что это вообще допустимый синтаксис; никогда не знал, что можно написать horrid T ar[] вне списка параметров функции.

3. @Tomalakgeret’kal: Насколько я помню, это обычное расширение, позволяющее использовать его в качестве последнего члена типа, так что вы можете выделить с помощью malloc(sizeof(A) 3) и притвориться, что b это массив B[4] .

4. @Mooing: Фу!??! В любом случае, неудивительно, что я не могу найти это в стандартах. Значит, это строго расширение реализации?

5. @avakar: Насколько я знаю, это функция C99. Однако этого нет ни в одной версии C .

Ответ №1:

B b[] вот «гибкий элемент массива«, нестандартное расширение в вашем компиляторе (взято из C99), которое позволяет вам объявлять неограниченный массив в качестве последнего элемента в типе. Это полезно только при выделении вашего объекта старомодным способом C (когда вы добавляете свой аргумент в malloc , чтобы освободить место для массива), и его следует избегать. В этом случае вы не выделили никакой дополнительной памяти для массива, поэтому в теле вашего конструктора, когда вы пытаетесь получить доступ к чему-то, что встречается на 3 «элемента» за пределами этого ничто, вы вызываете UB . Я проигнорирую расширение для остальной части моего ответа, поскольку ему действительно нет места в коде C .

Нет ли способа указать размер массива внутри конструктора?

Нет, такого не существует.

Границы массива должны быть известны во время компиляции, поэтому нет случая, когда вы знаете в теле вашего ctor больше, чем в определении класса; вам необходимо указать измерение в самом объявлении элемента:

 class A {
    B b[3];
};
  

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

 class A {
  public:
   A() : b(new B[3]) {}
  ~A() { delete[] b; }
  private:
    B* b;   // same as `B b[]`! but far clearer
};
  

Однако вместо этого я предлагаю std::vector :

 class A {
  public:
   A() : b(3) {}
  private:
    std::vector<B> b;
};
  

Комментарии:

1. B *b это не то же самое, что B b[] в данном контексте.

2. Было бы 1 за отличное объяснение, но за фактически неверные утверждения в первом абзаце.

3. @avakar, @Rob: Сегодня узнали кое-что новое! Теперь мой ответ должен быть полным. `

Ответ №2:

ДА. Используя для этого оператор new : b = new B[3]; . Объявите b как B *b . Конечно, вам нужно delete[] поместить его в деструктор.

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

Ответ №3:

C не поддерживает никаких типов с размером, определенным во время выполнения. Следовательно, у вас есть только варианты определения размера массива во время компиляции (возможно, с помощью параметра шаблона, отличного от типа) или перемещения массива из объекта путем создания b указателя и выделения памяти для него с помощью new (или, что лучше, позвольте стандартной библиотеке сделать это за вас с помощью vector ).

Ответ №4:

Это невозможно — чего бы вы ожидали от sizeof(A) для вычисления?! Если вам действительно нужна такая функциональность, используйте динамическое распределение, то есть закрытую переменную-член B *b, b(new B[3]) в списке инициализаторов конструкторов и удалите[] b; в деструкторе.