четверг, июня 10, 2010

Пост "Проблемы с delete[]"

В посте Проблемы с delete[] Александр рассказывает про undefined behavior вот такого кода:

A* a = new B[T];
delete[] a;

Рекомендую.

Updated 11.07.2010: Eugene K. справедливо уточняет
Вообще-то для получения проблем необязательно удалять. Достаточно выполнить какой-нибудь доступ к элементу "массива" a с индексом больше нуля.

A* a = new B[T];
a[1].p = 42; // запишет не туда

То есть проблема собственно в строке выделения "A* a = new B[T];". Если над ней помедитировать, то можно догадаться, что она лишена смысла.

13 коммент.:

Amesk комментирует...

Ccылка на блог Раймонда Чена в одном из комментариев [http://blogs.msdn.com/b/oldnewthing/archive/2004/02/03/66660.aspx], где обсуждается схожий вопрос, даже более интересна для изучения чем исходный пост

soonts комментирует...

Как обычно, нормальные ОС + IDE этой проблемой не затронуты: в мире Windows всё работает.

Eugene K. комментирует...

http://easy-coding.blogspot.com/2010/06/delete.html?showComment=1276182441327#c1419027836280113277

jia3ep комментирует...

Нафик использовать сишные массивы с С++ классами, да ещё с полиморфизмом? При смешивании всегда возникают проблемы.

huita комментирует...

В обсуждении так и не написали, как исправить код, чтобы избежать сегфола.

Alena комментирует...

2huita:

В обсуждении так и не написали, как исправить код, чтобы избежать сегфола.

Я бы использовала тут вектор, а не массив. jia3ep выше тоже на это намекнул...

legolegs комментирует...

А всё потому, что нету отдельных типов "указатель на массив", которые было бы запрещено приводить друг к другу.
Интересно, как с сабжем в ди?

NightmareZ комментирует...

Очевидно же.

shrike742 комментирует...

какбе, даже в Мейерсе написано, что так делать нехорошо, а афтор - малолетний негодяй. см. "Never treat arrays polymorphically"

Юрий комментирует...

Да уж. Хорошо было бы ввести аналог до-диезного атрибута класса sealed (или const, как в Java, например; означает запрет наследования) и запретить подобное выражение для классов без этого атрибута.

Шутка :) Там та-ка-а-я ниточка потянется…

Юрий комментирует...

Я бы использовала тут вектор, а не массив. jia3ep выше тоже на это намекнул...

Всё равно тип элемента придётся делать указателем (пусть и "умным"). Так что, что вектор, что массив…

vector<A*> v(T); v[1] = new B();
valarray<A*> x(T); x[1] = new B();
A **a = new (A*)[T]; a[1] = new B();

// ...

FOR_EACH_VECTOR_ITEM( v, item, if (item) { delete item; item = 0; } );
FOR_EACH_VALARRAY_ITEM( x, item, if (item) { delete item; item = 0; } );
FOR_EACH_ARRAY_ITEM( a, item, if (item) { delete item; item = 0; } );
delete[] a;

glad18 комментирует...

Здравствуйте Алёна!
Прошу прощения, я может быть один тут дурень такой, но чёт я не пойму в чём тут баг ?

Вот я написал:

class A
{
public:
A(): t(0) {};
virtual ~A(){};

int t;

};

class B: public A
{
public:
virtual ~B(){};
};

void main()
{
A* a = new B[3];
a[1].t = 3;
a[2].t = 5;
delete[] a;
}

всё прекрасно фурычит..

или я где-то допустил ошибку ? )

Alena комментирует...

glad18:

Здравствуйте Алёна!

Приветствую!

Прошу прощения, я может быть один тут дурень такой, но чёт я не пойму в чём тут баг ?

Посмотрите пост, на который я ссылаюсь: http://easy-coding.blogspot.com/2010/06/delete.html

Там подробно объяснено что именно не так, а также почему в VC++ проблемы не видны.