Ответ 1
Это не разбиение объектов.
Как отмечалось, индексирование myArray
не вызывает разбиение объектов, но приводит к поведению undefined, вызванному индексированием в массив Derived
, как если бы это был массив Base
.
Вид "ошибки распада массива".
Ошибка, введенная при назначении new Derived[42]
to myArray
, может быть изменением ошибки распада массива.
В истинном экземпляре такого типа ошибок существует реальный массив:
Derived x[42];
Base *myArray = x;
Проблема вводится потому, что массив Derived
распадается на указатель на Derived
со значением, равным адресу его первого элемента. Распад позволяет правильному выполнению указателя. Это поведение распада унаследовано от C, который был функцией разработки языка, позволяющей массивам "передаваться по ссылке".
Это приводит нас к еще худшему воплощению этой ошибки. Эта функция дает семантику C и С++ для синтаксиса массивов, которые превращают аргументы функции массива в псевдонимы для аргументов указателя.
void foo (Base base_array[42]) {
//...
}
Derived d[42];
foo(d); // Boom.
Однако new[]
на самом деле является перегруженным оператором, который возвращает указатель на начало выделенного объекта массива. Таким образом, это не истинный экземпляр распада массива (хотя используется распределитель массива). Тем не менее, признаки ошибки одинаковы, а намерение new[]
- получить массив Derived
.
Обнаружение и устранение ошибок.
Используйте интеллектуальный указатель.
Эту проблему можно избежать, используя объект интеллектуального указателя вместо управления необработанным указателем. Например, аналогичная ошибка кодирования с unique_ptr
будет выглядеть так:
std::unique_ptr<Base[]> myArray = new Derived[42];
Это приведет к ошибке времени компиляции, поскольку конструктор unique_ptr
explicit
Используйте контейнер и, возможно, std::reference
.
В качестве альтернативы вы можете избежать использования new[]
и использовать std::vector<Derived>
. Затем вы вынуждены были бы разработать другое решение для отправки этого массива в код рамки, который известен только Base
. Возможно, функция шаблона.
void my_framework_code (Base &object) {
//...
}
template <typename DERIVED>
void my_interface(std::vector<DERIVED> &v) {
for (...) {
my_framework_code(v[i]);
}
}
Или, используя std::reference_wrapper<Base>
.
std::vector<Derived> v(42);
std::vector<std::reference_wrapper<Base>> myArray(v.begin(), v.end());