Удаление псевдонима указателя

Делая это:

 union{
     int * integer;
     char * character;
 } u;
 u.integer = new int;
 delete u.character;

 u.integer = new int[5];
 delete [] u.character;

Я предполагаю, что это не сработает, если какой-либо из этих типов имеет нетривиальные деструкторы, но это нормально?


person zounds    schedule 23.09.2011    source источник
comment
Вот тесно связанный вопрос: stackoverflow.com/q/2140319/57428   -  person sharptooth    schedule 23.09.2011


Ответы (4)


Это не работает в любом случае, если мы предполагаем, что работа означает четко определенное поведение, а не видимость работы (т. е. отсутствие сбоев).

person Armen Tsirunyan    schedule 23.09.2011
comment
Это действительно не должно быть достаточно хорошо; Я мог бы дать ответ, в котором говорится, что это всегда будет работать, и он прекрасно определен, и у вас не будет возможности выбрать, какой из них правильный. - person Dennis Zickefoose; 23.09.2011

Нет, это поведение undefined независимо от того, имеет ли элемент тривиальный деструктор. Если деструктор тривиален, он может казаться "работающим", когда на самом деле происходит утечка памяти и т. д.

person Mark B    schedule 23.09.2011
comment
Возможно, это даже не утечка памяти ... она просто не определена :) - person Armen Tsirunyan; 23.09.2011

Я собираюсь сказать, что это где-то между реализацией определенной и неопределенной.

5.3.5/2: «В первом варианте (удалить объект) значение операнда удаления может быть… указателем на объект, не являющийся массивом, созданный предыдущим новым выражением….

Значение указателя не меняется при использовании так, как вы это сделали, поэтому это должно работать, как и ожидалось, при условии sizeof(char*) == sizeof(int*). Результат этого конкретного сравнения определяется реализацией, и если предположение ложно, то поведение не определено.

Так что это действительно не особенно безопасно.

person Dennis Zickefoose    schedule 23.09.2011

Легко видеть, что это опасная ошибка. Эти два типа могут иметь совершенно разные и несовместимые способы выделения и освобождения памяти. Это включает в себя заполнение, сборку мусора, бухгалтерию, манипуляции с памятью для конкретных классов и т. д. Просто не делайте этого.

#include <cstddef>
#include <cstdlib>
#include <iostream>

using namespace std;

class A
{

    public:

        void* operator new (size_t size)
        {
            cout << "A::operator new (size_t)" << endl;
            return malloc(size);
        }

        void* operator new [] (size_t size)
        {
            cout << "A::operator new [] (size_t)" << endl;
            return malloc(size);
        }

        void operator delete (void* ptr)
        {
            cout << "A::operator delete (void*)" << endl;
            free(ptr);
        }

        void operator delete [] (void* ptr)
        {
            cout << "A::operator delete [] (void*)" << endl;
            free(ptr);
        }

};

class B
{

    public:

        void* operator new (size_t size)
        {
            cout << "B::operator new (size_t) with some B-specific stuff" << endl;
            return malloc(size);
        }

        void* operator new [] (size_t size)
        {
            cout << "B::operator new [] (size_t) with some B-specific stuff" << endl;
            return malloc(size);
        }

        void operator delete (void* ptr)
        {
            cout << "B::operator delete (void*) with some B-specific stuff" << endl;
            free(ptr);
        }

        void operator delete [] (void* ptr)
        {
            cout << "B::operator delete [] (void*) with some B-specific stuff" << endl;
            free(ptr);
        }

};


int main (int, char**)
{

    union{
        A* a;
        B* b;
    } u;

    u.a = new A();
    delete u.b;

    u.a = new A[5];
    delete [] u.b;

}
person Frigo    schedule 24.09.2011