2013-12-13 1 views
5

Согласно C++ 03 12,4/12, когда деструктор вызывается явноЧто говорит C++ 03 12.4/12 о вызове деструктора базового класса явно через указатель?

, если объект не относится к типу класса деструктора, а не из класса, производного от типа класса деструктора, программа имеет неопределенное поведение

так что у меня этот код:

class Base {}; 
class Derived : public Base {}; 

char memory[100]; 
new(memory) Derived(); 
Base* ptr = (Base*)memory; 
ptr->~Base(); 

Здесь объект типа Derived и «тип класса деструктор» является Base и поэтому л ooks, как в соответствии со стандартной формулировкой, нет оснований для UB.

Значит, код выше дает UB в соответствии со стандартом?

+0

do обычно обычно предоставляют некоторые члены? – user1810087

+0

@itwasntpete: Ну, не обязательно. Например, вы можете создать новый класс исключений, который можно поймать отдельно, не добавляя новых членов. – sharptooth

+0

У меня есть догадка, что это UB, потому что 12.4/12 допускает форму 'производныйPtr-> ~ Base()' с целью поддержки виртуальных деструкторов. Однако здесь нет C++ 03. – MSalters

ответ

4

Правильно, нет неопределенного поведения.

В отличие есть потенциал UB в этом случае в зависимости от типов вовлеченных:

Base *ptr = new Derived(); 
delete ptr; 

Причина заключается в том, что для некоторых типов корректировка может быть применена к реализации, чтобы получить от Derived* до Base*. Таким образом, без указателя на полный объект нет возможности правильно освободить выделение памяти. Виртуальный деструктор гарантирует, что под-объект Base предоставляет достаточную информацию для реализации для восстановления (механизм виртуального вызова должен иметь возможность восстановить указатель Derived*, чтобы передать его как this).

Но в вашем примере память не освобождена, и поэтому нет мотивации сделать ее UB. Конечно, это еще плохая идея, так как концептуально объект Derived находится в неисправном состоянии. У вас нет законного способа позвонить ~Derived, даже. В вашем примере, хотя оба типа тривиально разрушаемы, поэтому нет нужно, чтобы вызвать деструктор.

+1

Эмм ... Регулировка?'Derived' может легко иметь' operator new() 'реализованный в другой куче, и это может привести к тяжелым последствиям даже без какой-либо корректировки. – sharptooth

+0

@sharptooth: да, хорошая точка. Если 'new' и' delete' не перегружены для этих типов, хотя, по-прежнему это UB по моей причине. –

+0

На самом деле пример new-delete - это UB в любом случае. Ваш пример и мой пример - это просто примеры того, что может сломаться. – sharptooth

0

, пожалуйста, исправьте меня, если я ошибаюсь, я думаю, что нет неопределенного поведения, но все же его следует избегать в сущности человечества (или поддержания целостности). но, рассмотрим, что Derived создает какой-либо элемент, например. общий указатель (который не является нетипичным даже для исключений :). я попробовал этот код на моей машине, а также на codepad:

class Base { 
public: 
    boost::shared_ptr<int> x; 
}; 
class Derived : public Base { 
public: 
    boost::shared_ptr<int> y; 
}; 


int main(int argc, char *argv[]) { 
    boost::shared_ptr<int> xx(new int(0xff)); 
    boost::shared_ptr<int> yy(new int(0xaa)); 

    int memory[100]; 
    for(int i=0; i<100; i++) 
    memory[i] = 0; 
    Derived* foo = new(memory) Derived(); 
    foo->x = xx; 
    foo->y = yy; 
    (*foo->y)--; 
    Base* ptr = (Base*)foo; 

    ptr->~Base(); 

    Derived* bar = new(memory) Derived(); 

    bar->x = xx; 
    bar->y = yy; 

    foo->~Derived(); 

    return 0; 
} 

здесь является то, что shared_ptr уу не выпустили, и никто не может гарантировать, чтобы никогда не забывать о Derived не должны предоставлять какие-либо вещи.

+1

Что-то не выпущенное не означает UB. – sharptooth

+0

В этом случае я думаю, что UB строит объект над памятью, занятой нетривиально разрушаемым объектом, который не был уничтожен. Итак, я думаю, что UB является вторым вызовом 'new (memory) Derived()', который записывает элемент 'y'. Но даже если я ошибаюсь, и это не UB, тогда 'bar-> y' является нулевым, поэтому разыгрывает его. [Это замечание касается кода кодекса, я просто заметил, что код здесь отличается.] –

1

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

+0

Это также применимо в Base Base = new Derived(); удалить базу; 'case? – sharptooth

+0

@sharptooth: Я бы зашел так далеко, чтобы сказать «да»; на самом деле, я бы подумал: «Базовая база; static_cast (& base) -> ~ Derived(); 'должен работать также (как это нелепо, как это звучит), потому что у обоих из них есть тривиальные деструкторы, а это значит, что их деструкторы не должны иметь никакого эффекта ... – Mehrdad

+0

Текст из стандарта, который цитируемый в вопросе, не имеет исключения для тривиальных деструкторов. Этот ответ ** не ** о неопределенном поведении, а о вероятных последствиях кода. –

 Смежные вопросы

  • Нет связанных вопросов^_^