#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; в деструкторе.