четверг, июня 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 комментариев:

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

    ОтветитьУдалить
  2. Анонимный10/6/10 18:44

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

    ОтветитьУдалить
  3. http://easy-coding.blogspot.com/2010/06/delete.html?showComment=1276182441327#c1419027836280113277

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

    ОтветитьУдалить
  5. Анонимный11/6/10 01:34

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

    ОтветитьУдалить
  6. 2huita:

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

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

    ОтветитьУдалить
  7. Анонимный11/6/10 16:28

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

    ОтветитьУдалить
  8. Анонимный18/6/10 01:01

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

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

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

    ОтветитьУдалить
  10. Я бы использовала тут вектор, а не массив. 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;

    ОтветитьУдалить
  11. Анонимный12/7/10 22:16

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

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

    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;
    }

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

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

    ОтветитьУдалить
  12. glad18:

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

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

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

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

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

    ОтветитьУдалить