Никак не могу понять, что в этом коде сделано неверно:
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;
class A
{
string name;
public:
A(const char *title):
name(title)
{
cout<<"A::A for '"<<name<<"'"<<endl;
}
~A()
{
cout<<"A::~A for '"<<name<<"'"<<endl;
}
};
class B
{
A ba;
public:
B():ba("b::a"){}
virtual ~B(){}
virtual void f(){}
};
class C : public B
{
A ca;
public:
C():ca("c::a"){}
};
int main()
{
B *ptr = new C[5];
delete[] ptr;
return 0;
}
На винде в MSVC вроде работает, а в GCC на линуксе и маке вижу следующее поведение:
A::A for 'b::a'
A::A for 'c::a'
A::A for 'b::a'
A::A for 'c::a'
A::A for 'b::a'
A::A for 'c::a'
A::A for 'b::a'
A::A for 'c::a'
A::A for 'b::a'
A::A for 'c::a'
Segmentation fault
Что я делаю не так?
WBW, Mike.
Re: Создание и удаление массива виртуальных объектов
Вы адресуете массив элементов одного типа (C) указателем на другой тип (B), а происходит это
при удалении массива (delete [] ptr). Операция delete в данном случае логически эквивалентна
обходу всех элементов и вызову их деструкторов через указатель на B. А поскольку размеры
типов B и C различны, различается и арифметика соответствующих указателей — B имеет другой размер "шага".
То, что типы связаны наследованием, к делу отношения не имеет.
Та же ситуация возникает, если попытаться вызвать метод f() одного из элементов (кроме первого):
int main()
{
B *ptr = new C[5];
ptr[3].f(); // << та же ошибкаdelete[] ptr;
return 0;
}
Видимо, компилятор от MS где-то сохраняет тип элементов массива, поэтому приведенный Вами код
"прокатывает", хотя и не должен, на мой взгляд.
Re: Создание и удаление массива виртуальных объектов
МЛ>Что я делаю не так?
Как уже писали выше (непонятно, почему минусы поставили) массивы нельзя трактовать полиморфно.
В твоей ситуации тебе надо создавать массив указателей на объекты, а не массив объектов. А еще лучше, вектор. Примерно так:
vector<B*> vec;
vec.reserve(SIZE);
for (int i = 0; i < SIZE; ++i)
vec.push_back(new C);
....
for (vec<B*>::iterator b = vec.begin(), e = vec.end(), b! = e; ++b)
delete(*b);
}
Да здравствует мыло душистое и веревка пушистая.
Re: Создание и удаление массива виртуальных объектов
okman wrote:
> Видимо, компилятор от MS где-то сохраняет тип элементов массива, поэтому > приведенный Вами код > "прокатывает", хотя и не должен, на мой взгляд.
Именно так, об этой фиче немало топиков написано.
Posted via RSDN NNTP Server 2.1 beta
Re[2]: Создание и удаление массива виртуальных объектов
V>vector<B*> vec;
V>vec.reserve(SIZE);
V>for (int i = 0; i < SIZE; ++i)
V> vec.push_back(new C);
V>
Ну, прямо так, когда vec — локальная переменная, конечно, нельзя — любая неприятность, в виде исключения, в push_back, операторе new, или, не дай Бог, в конструкторе С, и будет утечка памяти.
Майерс даже не смог пройти мимо этой темы — так и говорил, дескать, "never treat arrays polymorphically" и баста.
Если не поможет, будем действовать током... 600 Вольт (C)
Re: Создание и удаление массива виртуальных объектов
Здравствуйте, okman, Вы писали:
O>Здравствуйте, Ytz, Вы писали:
O>...
Ytz>>Заодно не надо помнить про delete. Я вообще всегда настораживаюсь когда вижу в коде delete
O>А я настораживаюсь, когда вижу new и не вижу delete...
Могу только посочувствовать — ловить утечки памяти дело тяжелое, но неблагодарное.
Re[3]: Создание и удаление массива виртуальных объектов