Re[7]: Уничтожение лок. переменных!!!???
От: Анатолий Широков СССР  
Дата: 03.10.03 10:30
Оценка:
Рассмотри безопасный вызов деструктора:

class foo
{
public:
    int i;

    ~foo() 
    {
    }    
    void func() 
    { 
        i = 10;
    }
};

class boo
{
public:
    foo f;
};

int main()
{
   boo b;
   // разрушили состояние объекта f, но память у него никто еще не отбирал     
   b.f.~foo(); 
   // поэтому никаких сбоев в следующим вызове нет
   b.f.func();
}


Теперь изменим пример:

class foo
{
public:
    int *i;

    foo() : i(new int(0)) 
    {
    }
    foo(const foo &other) : i(new int(*(other.i))) 
    {
    }    
    foo& operator = foo(const foo &other)
    {
        foo(ohter).swap(*this);
        return *this;
    }    
    ~foo() 
    {
        delete i;
    }    

    void swap(foo &other)
    {
       std::swap(i, other.i);
    } 

    void func() { *i = 10;}
};

class boo
{
public:
    foo f;
};

int main()
{
   boo b;
   // разрушили состояние объекта f     
   b.f.~foo(); 
   // после вызова деструктора i указывает черт знает куда
   // присваивание в методе func приведет к ошибке общей защиты
   b.f.func(); // вываливаемся
}
Re[8]: Уничтожение лок. переменных!!!???
От: avch  
Дата: 03.10.03 10:38
Оценка:
Здравствуйте, Анатолий Широков, Вы писали:

АШ>Рассмотри безопасный вызов деструктора:


АШ>
АШ>class foo
АШ>{
АШ>public:
АШ>    int i;

АШ>    ~foo() 
АШ>    {
АШ>    }    
АШ>    void func() 
АШ>    { 
АШ>        i = 10;
АШ>    }
АШ>};

АШ>class boo
АШ>{
АШ>public:
АШ>    foo f;
АШ>};

АШ>int main()
АШ>{
АШ>   boo b;
АШ>   // разрушили состояние объекта f, но память у него никто еще не отбирал     
АШ>   b.f.~foo(); 
АШ>   // поэтому никаких сбоев в следующим вызове нет
АШ>   b.f.func();
АШ>}
АШ>


АШ>Теперь изменим пример:


АШ>
АШ>class foo
АШ>{
АШ>public:
АШ>    int *i;

АШ>    foo() : i(new int(0)) 
АШ>    {
АШ>    }
АШ>    foo(const foo &other) : i(new int(*(other.i))) 
АШ>    {
АШ>    }    
АШ>    foo& operator = foo(const foo &other)
АШ>    {
АШ>        foo(ohter).swap(*this);
АШ>        return *this;
АШ>    }    
АШ>    ~foo() 
АШ>    {
АШ>        delete i;
АШ>    }    

АШ>    void swap(foo &other)
АШ>    {
АШ>       std::swap(i, other.i);
АШ>    } 

АШ>    void func() { *i = 10;}
АШ>};

АШ>class boo
АШ>{
АШ>public:
АШ>    foo f;
АШ>};

АШ>int main()
АШ>{
АШ>   boo b;
АШ>   // разрушили состояние объекта f     
АШ>   b.f.~foo(); 
АШ>   // после вызова деструктора i указывает черт знает куда
АШ>   // присваивание в методе func приведет к ошибке общей защиты
АШ>   b.f.func(); // вываливаемся
АШ>}
АШ>


C динамическими переменными все понятно хорошо...
Получается что память из под статических объектов занята до конца main() ???
А что если объект содержит много данных, они что до конца проги будут занимать память???
Re[10]: Уничтожение лок. переменных!!!???
От: Анатолий Широков СССР  
Дата: 03.10.03 10:39
Оценка:
A>Непонятно, почему состояние объекта разрушается а его структура в памяти остается??? Как то это убого, зачем
A>оставлять объект в памяти если он уничтожен деструкторм

Во в этом и есть твое заблуждение. Деструктор не освобождает память отведенную под объект.
Re[11]: Уничтожение лок. переменных!!!???
От: Lorenzo_LAMAS  
Дата: 03.10.03 10:42
Оценка:
Возможно, это дельфист проник в форум по С++, отсюда стремление убивать объекты, собственноручно вызывая деструктор, и непонимание того, почему программа работает.
Of course, the code must be complete enough to compile and link.
Re[11]: Уничтожение лок. переменных!!!???
От: avch  
Дата: 03.10.03 10:45
Оценка:
Здравствуйте, Анатолий Широков, Вы писали:

A>>Непонятно, почему состояние объекта разрушается а его структура в памяти остается??? Как то это убого, зачем

A>>оставлять объект в памяти если он уничтожен деструкторм

АШ>Во в этом и есть твое заблуждение. Деструктор не освобождает память отведенную под объект.


Ты же сам написал что состояние объекта разрушается, а память остается. Для чего, раз объекта логически
нет. Кроме этого проиходит вызов ф-ии и она работает . Это вообще бредово....Что происходит с памятью, почему она не
освобождается также как и в случае динамического создания?
Re[12]: Уничтожение лок. переменных!!!???
От: avch  
Дата: 03.10.03 10:48
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Возможно, это дельфист проник в форум по С++, отсюда стремление убивать объекты, собственноручно вызывая деструктор, и непонимание того, почему программа работает.


D тут не причем... Там такая же штука...
Re[9]: Уничтожение лок. переменных!!!???
От: Анатолий Широков СССР  
Дата: 03.10.03 10:48
Оценка:
A>C динамическими переменными все понятно хорошо...
A>Получается что память из под статических объектов занята до конца main() ???
A>А что если объект содержит много данных, они что до конца проги будут занимать память???

Понятно, вам нужно понять концепцию времени жизни объекта:

boo global; // глобальный объект, живет до конца работы программы

void func()
{
   {
      boo local1; // автоматические объект, живет с момента объявление до выхода из области действия
   } // вот здесь объект local1 уничтожается

   boo local2; //
} // вот здесь объект local2 уничтожается

int main()
{
    boo* dynamic = new boo; // динамический объект, живет до вызова delete

    delete dynamic; // возвращаем память системе

    // вот здесь уже никакого объекта, на который указывает dynamic нет.
}
Re[12]: Уничтожение лок. переменных!!!???
От: Sergey Россия  
Дата: 03.10.03 10:49
Оценка:
Hello, avch!
You wrote on Fri, 03 Oct 2003 10:45:18 GMT:

АШ>> Во в этом и есть твое заблуждение. Деструктор не освобождает память

АШ>> отведенную под объект.

a> Ты же сам написал что состояние объекта разрушается, а память остается.

a> Для чего, раз объекта логически нет.

Например, чтобы на этом месте разместить новый объект при помощи placement формы new.

a> Кроме этого проиходит вызов ф-ии и

a> она работает . Это вообще бредово....

А почему она не должна работать?

a> Что происходит с памятью,


Ровным счетом ничего.

a> почему

a> она не освобождается также как и в случае динамического создания?

Потому что так и было задумано.

Best regards,
Sergey.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[12]: Уничтожение лок. переменных!!!???
От: alexandrov_alex США  
Дата: 03.10.03 10:53
Оценка:
Здравствуйте, avch, Вы писали:

Гражданин, все дело в том, что освобождение памяти еще не значит, что она тут же будет перезаписана. Ее содержимое может оставаться нетронутым еще сколько угодно времени. Пока другой не займет.

-- Всего хорошего!
-- Alex Alexandrov, e-mail: alexandrov_alex@fromru.com
Posted via RSDN NNTP Server 1.7 "Bedlam"
It's kind of fun to do the impossible (Walt Disney)
Re[12]: Уничтожение лок. переменных!!!???
От: Анатолий Широков СССР  
Дата: 03.10.03 10:54
Оценка:
Здравствуйте, avch, Вы писали:

A>Здравствуйте, Анатолий Широков, Вы писали:


A>>>Непонятно, почему состояние объекта разрушается а его структура в памяти остается??? Как то это убого, зачем

A>>>оставлять объект в памяти если он уничтожен деструкторм

АШ>>Во в этом и есть твое заблуждение. Деструктор не освобождает память отведенную под объект.


A>Ты же сам написал что состояние объекта разрушается, а память остается. Для чего, раз объекта логически

A>нет. Кроме этого проиходит вызов ф-ии и она работает . Это вообще бредово....Что происходит с памятью, почему она не
A>освобождается также как и в случае динамического создания?

Еще раз повторю, понятие "состояние" не тождественно понятию "память" — деструктор не имеет информации о природе памяти, выделенной под объект.
Re[13]: Уничтожение лок. переменных!!!???
От: avch  
Дата: 03.10.03 10:57
Оценка:
Здравствуйте, alexandrov_alex, Вы писали:

_>Здравствуйте, avch, Вы писали:


_>Гражданин, все дело в том, что освобождение памяти еще не значит, что она тут же будет перезаписана. Ее содержимое может оставаться нетронутым еще сколько угодно времени. Пока другой не займет.


_>-- Всего хорошего!

_>-- Alex Alexandrov, e-mail: alexandrov_alex@fromru.com

Теперь понятно
Re[13]: Уничтожение лок. переменных!!!???
От: Аноним  
Дата: 03.10.03 11:00
Оценка:
Память (стек в данном случае)не "занимается", наверное, до окончания области действия объекта.
Re: Уничтожение лок. переменных!!!???
От: MagIH Россия  
Дата: 05.10.03 04:13
Оценка: 3 (1) -2
Здравствуйте, avch, Вы писали:

A>Привет всем!!!

A>Вот такой код в VC6 билдится да еще и без ошибок RT выполняется:

Всё правильно. За исключением того, что смысла в таком коде мало. А как м почему это работает объясняется легко. В нескольких письмах я тут видел ссылки на стандарт C++. Но если Вы читали стандарт, господа, то там чётко разделяются физический (как что-то должно работать) и логический (что это означает) уровни. Отсюда и путанница. Про оператор delete и про деструктор часто говорят, что они "разрушают" объект. Кстати — а в чём тогда разница между ними? Ответ прост — деструктор, в соответствии со стандартом, это ФУНКЦИЯ, вызываемая перед разрушением объекта (заметьте отличие от "функция разрушающая объект"). Стандарт так же чётко и ясно оговариват время жизни объекта (то есть его состояния в памяти) и условия, когда деструктор будет вызван автоматически (оператор delete, разрушение переменных в стеке по выходу из функции, разрушение членов данных объекта, разрушение глобальных переменых...). При этом, Вы имеете полное (закреплённое стандартом) право вызывать деструктор, как и любую другую функцию, в течение времени жизни объекта сколько угодно раз. И ничего с самим "объектом" = "состоянием объекта" = "областью памяти, занимаемая данными-членами класса объекта" не произойдет (кроме того, что вы сами явно опрелили в деструкторе, как и в любой другой функции). Поэтому то данный пример и работает. Деструктор то просто выводит строку на экран. Так что объект то и не догадывается, что его пытались прикончить... Кстати во всех примерах где возникаяли явные RunTime ошибки — в деструкторе объект портился явно, так, что использование его переменных или повторный вызов деструктора при разрушении объекта (в "стандартной" ситуации) и вызывало сообщение об ошибке. Теперь об операторе delete. Он отличается тем, что делает два действия — вызывает деструктор и затем — освобождает память, выделнную под переменные объекта (впрочем оговорюсь, что delete может быть переопределён и делать что-то иное).
Поэтому если в данном примере заменить локальную переменную на указатель на объект в сосдавать объект с помощью оператора new, а затем вместо деструктора вызвать delete — то в том же примере вылезет сообщение об ошибке, так как в этом случае "объект" = "состояние объекта" = "область памяти, занимаемая данными-членами класса объекта" будет ДЕЙСТВИТЕЛЬНО разрушена. (При использовании стандартного delete
Re[2]: Уничтожение лок. переменных!!!???
От: WolfHound  
Дата: 05.10.03 09:23
Оценка:
Здравствуйте, MagIH, Вы писали:

MIH>Всё правильно. За исключением того, что смысла в таком коде мало.

Да ну тут undefined behavior во всей красе
MIH>А как м почему это работает объясняется легко.
Очень. Одно из проявлений undefined behavior рабочая программа.

То что дальше один сплошной гон. Деструктор это именно функция разрушающея объект те после его работы остается сырая память и даже если там остается фактически инвариант объекта то пользоватся им всеравно нельзя иначе undefined behavior. А то что перед разрушением самого объекта можно выполнить свой код это не отменяет разрушение объекта деструктором. Для того чтобы на томже месте создать новый объект нужно вызвать placement new те конструктор.

Оператор delete сначала вызывает деструктор это ты у него не как не отнимишь, а потом должен освободить память которую выделил new менно функцию освобождающею память и можно перегрузить но в нее в любом случае попадет указатель на мертвый объект.
... << RSDN@Home 1.1 beta 2 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[2]: Уничтожение лок. переменных!!!???
От: leper Россия  
Дата: 05.10.03 11:11
Оценка:
Здравствуйте, MagIH, Вы писали:

MIH>Здравствуйте, avch, Вы писали:


A>>Привет всем!!!

A>>Вот такой код в VC6 билдится да еще и без ошибок RT выполняется:

MIH>Всё правильно. За исключением того, что смысла в таком коде мало. А как м почему это работает объясняется легко. В нескольких письмах я тут видел ссылки на стандарт C++. Но если Вы читали стандарт, господа, то там чётко разделяются физический (как что-то должно работать) и логический (что это означает) уровни. Отсюда и путанница. Про оператор delete и про деструктор часто говорят, что они "разрушают" объект. Кстати — а в чём тогда разница между ними? Ответ прост — деструктор, в соответствии со стандартом, это ФУНКЦИЯ, вызываемая перед разрушением объекта (заметьте отличие от "функция разрушающая объект"). Стандарт так же чётко и ясно оговариват время жизни объекта (то есть его состояния в памяти) и условия, когда деструктор будет вызван автоматически (оператор delete, разрушение переменных в стеке по выходу из функции, разрушение членов данных объекта, разрушение глобальных переменых...). При этом, Вы имеете полное (закреплённое стандартом) право вызывать деструктор, как и любую другую функцию, в течение времени жизни объекта сколько угодно раз.

1. Уточно, пожалуйста, где в стандарте такое сказано?
2. Согласно пункту 3.8.1:

The lifetime of an object of type T ends when:
— if T is a class type with a nontrivial destructor (12.4), the destructor call starts, or
— the storage which the object occupies is reused or released.

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

Все остальное, как уже говорилось, от лукавого (т.е. от undefined behavior)
... << RSDN@Home 1.1 beta 1 >>
Think for yourself. Question authory.
Re[3]: Уничтожение лок. переменных!!!???
От: MagIH Россия  
Дата: 05.10.03 11:36
Оценка:
Здравствуйте, WolfHound, Вы писали:

MIH>>Всё правильно. За исключением того, что смысла в таком коде мало.

WH>Да ну тут undefined behavior во всей красе
MIH>>А как м почему это работает объясняется легко.
WH>Очень. Одно из проявлений undefined behavior рабочая программа.

Легко сказать "undefined behavior" когда не понимаешь, как это работает. Попытайся заодно объяснить, почему этот код будет работать одинакого на ЛЮБОЙ платформе, если его поведение "не предсказуемо"...

WH>То что дальше один сплошной гон. Деструктор это именно функция разрушающея объект те после его работы остается сырая память и даже если там остается фактически инвариант объекта то пользоватся им всеравно нельзя иначе undefined behavior. А то что перед разрушением самого объекта можно выполнить свой код это не отменяет разрушение объекта деструктором. Для того чтобы на томже месте создать новый объект нужно вызвать placement new те конструктор.

Интересное заявление. Может быть укажешь — откуда конкренто ты это взял? Хотя бы место в стандарте C++, где такое написано... Кроме того — если бы это было правдой — то в чём заключалось бы различие между деструктором и оператором delete? И наконец, посмотри ради интереса дезассемблированный код люой программы — которая явно вызывает деструктор. Я смотрел дезассемблированый код VC++, GNU и Watcom — код аналогичен и разрушения объекта там не происходит.

WH>Оператор delete сначала вызывает деструктор это ты у него не как не отнимишь, а потом должен освободить память которую выделил new менно функцию освобождающею память и можно перегрузить но в нее в любом случае попадет указатель на мертвый объект.

— Всё правильно, однако чем это противоречит тому, что я писал? Как раз таки — подтверждает. Область памяти, занимаемая объектом, после вызова деструктора — прекрасно остаётся, но вот пользоваться ей — без инициализации — черевато, потому её надо либо освободить, либо переинициализировать...

P.S. Повторять слова Энштейна и быть им — вещи разные...
Re[2]: Уничтожение лок. переменных!!!???
От: WFrag США  
Дата: 05.10.03 12:52
Оценка:
Здравствуйте, MagIH, Вы писали:

MIH>>Всё правильно. За исключением того, что смысла в таком коде мало. А как м почему это работает объясняется легко. В нескольких письмах я тут видел ссылки на стандарт C++. Но если Вы читали стандарт, господа, то там чётко разделяются физический (как что-то должно работать) и логический (что это означает) уровни. Отсюда и путанница. Про оператор delete и про деструктор часто говорят, что они "разрушают" объект. Кстати — а в чём тогда разница между ними? Ответ прост — деструктор, в соответствии со стандартом, это ФУНКЦИЯ, вызываемая перед разрушением объекта (заметьте отличие от "функция разрушающая объект"). Стандарт так же чётко и ясно оговариват время жизни объекта (то есть его состояния в памяти) и условия, когда деструктор будет вызван автоматически (оператор delete, разрушение переменных в стеке по выходу из функции, разрушение членов данных объекта, разрушение глобальных переменых...). При этом, Вы имеете полное (закреплённое стандартом) право вызывать деструктор, как и любую другую функцию, в течение времени жизни объекта сколько угодно раз. И ничего с самим "объектом" = "состоянием объекта" = "областью памяти, занимаемая данными-членами класса объекта" не произойдет (кроме того, что вы сами явно опрелили в деструкторе, как и в любой другой функции). Поэтому то данный пример и работает. Деструктор то просто выводит строку на экран. Так что объект то и не догадывается, что его пытались прикончить... Кстати во всех примерах где возникаяли явные RunTime ошибки — в деструкторе объект портился явно, так, что использование его переменных или повторный вызов деструктора при разрушении объекта (в "стандартной" ситуации) и вызывало сообщение об ошибке.


Гон. Вот тупое опровержение (все VC, до которых дотянулись руки — VC6.0, VC7.0, VC7.1):

#include <iostream>

struct A
{
    virtual ~A() { } // Типа не портим объект явно.
    virtual void func() = 0;
};

struct B : public A
{
    virtual void func() { std::cout << "Yo!" << std::endl; }
};

int main()
{
    A& a = B();
    a.~A(); // Деструктор типа нифига не делает, объекту все параллельно. ;)
    a.func(); // Ооопс. А вот и нет!
}


MIH>> Теперь об операторе delete. Он отличается тем, что делает два действия — вызывает деструктор и затем — освобождает память, выделнную под переменные объекта (впрочем оговорюсь, что delete может быть переопределён и делать что-то иное).


Оператор delete переопределен не может быть. Может быть переопределена функция (ее еще иногда называеют операторной функцией) delete. Оператор delete делает всегда одну и ту же последовательность действий — вызов деструктора, вызов соответствующей операторной функции. Вроде так.
Re[3]: Уничтожение лок. переменных!!!???
От: MagIH Россия  
Дата: 05.10.03 13:24
Оценка:
Здравствуйте, leper, Вы писали:

L>Здравствуйте, MagIH, Вы писали:


MIH>>Здравствуйте, avch, Вы писали:


A>>>Привет всем!!!

A>>>Вот такой код в VC6 билдится да еще и без ошибок RT выполняется:

MIH>>Всё правильно. За исключением того, что смысла в таком коде мало. А как м почему это работает объясняется легко. В нескольких письмах я тут видел ссылки на стандарт C++. Но если Вы читали стандарт, господа, то там чётко разделяются физический (как что-то должно работать) и логический (что это означает) уровни. Отсюда и путанница. Про оператор delete и про деструктор часто говорят, что они "разрушают" объект. Кстати — а в чём тогда разница между ними? Ответ прост — деструктор, в соответствии со стандартом, это ФУНКЦИЯ, вызываемая перед разрушением объекта (заметьте отличие от "функция разрушающая объект"). Стандарт так же чётко и ясно оговариват время жизни объекта (то есть его состояния в памяти) и условия, когда деструктор будет вызван автоматически (оператор delete, разрушение переменных в стеке по выходу из функции, разрушение членов данных объекта, разрушение глобальных переменых...). При этом, Вы имеете полное (закреплённое стандартом) право вызывать деструктор, как и любую другую функцию, в течение времени жизни объекта сколько угодно раз.

L>1. Уточно, пожалуйста, где в стандарте такое сказано?
L>2. Согласно пункту 3.8.1:
L>

L>The lifetime of an object of type T ends when:
L>— if T is a class type with a nontrivial destructor (12.4), the destructor call starts, or
L>— the storage which the object occupies is reused or released.

L>т.е. после вызова деструктора время жизни объекта закончилось, говорить о многократном вызове бессмыслено.

L>Все остальное, как уже говорилось, от лукавого (т.е. от undefined behavior)


Вот уж вопрос, содержащий ответ... Отвечу так: мест, которые описывают данную ситуацию в стандрте — несколько. Как только я доберусь до стандарта в понедельник, я постараюсь их перечислить (с цитатами). Кроме того, даже в приведённой цитате хочется выделить — nontrivial destructor (поинтересуйтесь господа заодно — что это за деструктор)... В нашем случае деструктор то как раз trivial
Не бросается ли вам в глаза — лёгкое противоречие в приведённой цитате из стандарта? "Время жизни объекта T заканчивается с началом вызова нетривиальнго деструктора"... Но если время жизни объекта закончилось (что, как мне кажется Вы трактуете как то, что объекта больше нет) — то какое право деструктор имеет делать какие либо операции над переменными объекта? Это так же будет "undefined behavior" А ведь именно в проведении заключительных действий над переменными объекта и заключается смысл деструктора...
Разрешить эту загадку просто — речь идёт о времени жизни объекта — для внешних по отношению к нему объектов. Или же если копнуть чуть глубже — то есть различие между временем жизни объекта как ЛОГИЧЕСКОГО понятия и как ФИЗИЧЕСКОЙ сущьности. Или же по другому (в более привычных терминах) — есть различие между временем жизни объекта и области памяти, занимаемой объектом. Во-первых — оба времени жизни оговариваются стандартом, а во-вторых — приведённая цитата описывает время жизни объекта (или же время жизни объекта как логического понятия). Вот тогда приведённая цитата обретает смысл — действительно, как только началась деинициализация переменных объекта, он как целостное логическое понятие теряет смысл... Но вот область памяти то прекрасно продолжает жить и никуда не девается! Более того, стандарт так же чётко оговаривает её время жизни. И общий смысл замысловатых правил таков — она продолжает относится к объекту — пока не освобождена и отдана системе (при освобождении динамически выделенной памяти или, например, выхода из функции, в стеке которой был размещён объект) и ваша программа сама не решит, что пора бы задействовать её по-другому (заняв другим объектом — того же и или иного типа). Стандарт оговаривает лишь, что у Вас её не отберут добровольно-принудительно просто поставив перед фактом — что она вам больше не пренадлежит.
Теперь рассмотрим, что такое "нетривиальный" деструктор и почему подчёркивается, что если деструктор "нетривиальный", то объект уничтожается (lifetime ends), а если тривиальный — объект по-прежнему существует.
Рассмотрим объект, который в начале своей работы резервирует динамическую память и кучу других объектов. (Например, картинку, которая в добавок создаёт объекты GDI — для своего отображения в окне или на экране.) И предположим, что и память и объекты — разрушаются в деструкторе (что вполне естественно). Так вот — вызвали мы деструктор (не важно как — сами или стандартным способом). Что произойдет? Деструктор освободит все эти объекты и память. И хотя область памяти объекта осталась такой же, какой и была — можно ли пользоваться объектом? Скорее всего — нет, указатели — или NULL (при аккуратном написании) или указывают неизвестно куда (на освобождённую память). То есть как логическое понятие объект перестаёт существовать. (Хотя остаётся пока как физическая сущность). Пользоваться им может быть весьма проблематично — если вообще возможно. Более того, если вызвать деструктор такого объекта вручную, а затем дождаться, когда деструктор будет вызван автоматически — скорее всего (например, если указатели осбобождены но не обнулены) возникнет RunTime Error. Вот как раз мы и получили пример объекта с "нетривиальным" деструктором. Замечу, что в общем случае оставить память или переинициализировать её в деструкторе — нельзя, так как деструктор не занает — вызвали ли его вручную или он вызван автоматически... (Хотя есть способы извратиться и сообщить ему об этом).
Теперь рассмотрим другой сценарий. Объект, который состоит сплошь из данных-членов класса простых типов — без каких либо резервирований памяти и т.п. То есть простая структура с методами — один из котрых — деструктор. Кроме того, допустим, что деструктор не "портит" состояние объекта, так что после этого объект теряем смысл (а это как раз та ситуация, которую привел в своём примере avch). То это как раз и есть — "тривиальный" деструктор. И мы можем вызывать его сколь угодно много раз — поведение программы будет столь же определено, как и при вызове любого другого метода класса. Объект прекрасно продолжает существовать не только как физическая сущьность, но и как логическое понятие. Вот почему в цитате оговаривается, что время жизни объекта заканчивается лишь при вызове нетривиального деструктора (пример которого приведён выше).
В общем ситуация с многократным вызовом деструктора — даже когда программа работает корректно и предсказуемо — это лазейка в стандарте C++ — нарушение закона, в рамках соблюдения его правил.
Так почему же тем не меннее не пользуются явным вызовом деструктора (за исключением некоторых ситуаций)? Потому — что тот же стандарт написан в рамках некоторых предположений, неписанных правил, которым тем не менее стремятся следовать. Одно из таких правил — раcширяемость. Ну допустим, сегодня деструктор Вашего объекта тривиален — и Вы зачем то стали вызывать его явно. Написали огромный код... А потом выяснилось, что объект надо расширить — правда при этом его деструктор перестаёт быть тривиальным... Может оказаться дешевле писать код с нуля...
Re[3]: Уничтожение лок. переменных!!!???
От: MagIH Россия  
Дата: 05.10.03 13:48
Оценка:
Здравствуйте, WFrag, Вы писали:

WF>Гон. Вот тупое опровержение (все VC, до которых дотянулись руки — VC6.0, VC7.0, VC7.1):


WF>
WF>#include <iostream>

WF>struct A
WF>{
WF>    virtual ~A() { } // Типа не портим объект явно.
WF>    virtual void func() = 0;
WF>};

WF>struct B : public A
WF>{
WF>    virtual void func() { std::cout << "Yo!" << std::endl; }
WF>};

WF>int main()
WF>{
WF>    A& a = B();
WF>    a.~A(); // Деструктор типа нифига не делает, объекту все параллельно. ;)
WF>    a.func(); // Ооопс. А вот и нет!
WF>}
WF>


Прекрасный пример. Однако замечу, что неприятность возникла при использовании ВИРТУАЛЬНОЙ функции. И связана с тем, что для большинства платформ (не берусь утверждать что для всех) деструктор любого объекта, использующего виртуальные функции является не тривиальным (см. письмо от leper). Что этот пример и подтверждает прекрасно. Однако это уже особенности трансляторов (которые играются с таблицами виртуальных функций), а не требование стандарта.

MIH>>> Теперь об операторе delete. Он отличается тем, что делает два действия — вызывает деструктор и затем — освобождает память, выделнную под переменные объекта (впрочем оговорюсь, что delete может быть переопределён и делать что-то иное).


WF>Оператор delete переопределен не может быть. Может быть переопределена функция (ее еще иногда называеют операторной функцией) delete. Оператор delete делает всегда одну и ту же последовательность действий — вызов деструктора, вызов соответствующей операторной функции. Вроде так.


А вот это святая правда. Каюсь. Оператор delete действительно не может быть переопеределён и действительно последовательнось вызовов так же фиксирована. Тут я выразился весьма коряво...
Re[4]: Уничтожение лок. переменных!!!???
От: Павел Кузнецов  
Дата: 06.10.03 08:47
Оценка: 11 (2)
Здравствуйте, MagIH, Вы писали:

L>> 2. Согласно пункту 3.8.1:

L>>

L>> The lifetime of an object of type T ends when:
L>> — if T is a class type with a nontrivial destructor (12.4), the
L>> destructor call starts, or — the storage which the object
L>> occupies is reused or released.

т.е. после вызова деструктора

L>> время жизни объекта закончилось, говорить о многократном
L>> вызове бессмыслено.

L>> Все остальное, как уже говорилось, от лукавого (т.е. от undefined behavior)


M> Вот уж вопрос, содержащий ответ... Отвечу так: мест, которые

M> описывают данную ситуацию в стандрте — несколько. Как только я
M> доберусь до стандарта в понедельник, я постараюсь их перечислить (с
M> цитатами).

Вот с этого лучше и начать, вместо того, чтобы приводить свои досужие рассуждения,
не имеющие никакого отношения к стандарту, да еще и подобным менторским тоном.

M> Кроме того, даже в приведённой цитате хочется выделить — nontrivial destructor

M> (поинтересуйтесь господа заодно — что это за деструктор)... В нашем случае деструктор
M> то как раз trivial

Учим мат. часть:

12.4/3 A destructor is trivial if it is an implicitly-declared
destructor and if:
— all of the direct base classes of its class have trivial destructors
— for all of the non-static data members of its class that are of class type
(or array thereof), each such class has a trivial destructor.
4 Otherwise, the destructor is nontrivial.


M> Не бросается ли вам в глаза — лёгкое противоречие в приведённой

M> цитате из стандарта? "Время жизни объекта T заканчивается с началом
M> вызова нетривиальнго деструктора"... Но если время жизни объекта
M> закончилось (что, как мне кажется Вы трактуете как то, что объекта
M> больше нет)

Легкий, но не вполне корректный способ ведения спора: приписать оппоненту некоторое
неверное высказывание, и опровергнуть его.

M> — то какое право деструктор имеет делать какие либо операции над переменными объекта?

M> Это так же будет "undefined behavior"
M> А ведь именно в проведении заключительных
M> действий над переменными объекта и заключается смысл деструктора...

Читать, по меньшей мере, 3.8, 12.7 и 12.6.2.

M> Разрешить эту загадку просто — речь идёт о времени жизни объекта — для внешних по отношению

M> к нему объектов.

Это твои домыслы. Вместо этого стандарт совершенно четко оговаривает, что именно можно делать
с объектом во все этапы, связанные с его существованием:
1. Когда память для будущего объекта уже выделена, но время жизни объекта еще не началось
(отдельно описано, в основном, в 3.8, 12.7 и 12.6.2).
2. После начала, но до конца времени жизни ("основная" часть стандарта):

3.8/3 The properties ascribed to objects throughout this International Standard
apply for a given object only during its lifetime.

3. После конца времени жизни, но до освобождения памяти; при этом, непосредственно для
выполнения деструктора, делаются некоторые "реверансы", разрешающие вызов функций-членов,
обращение к данным-членам и т.п. (в основном, там же, где и 1).

M> Или же если копнуть чуть глубже — то есть различие между временем жизни объекта как

M> ЛОГИЧЕСКОГО понятия и как ФИЗИЧЕСКОЙ сущьности. Или же по другому (в более привычных
M> терминах) — есть различие между временем жизни объекта и области
M> памяти, занимаемой объектом.

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

3.8/6 <...> after the lifetime of an object has ended and before the storage
which the object occupied is reused or released, any lvalue which refers to the original
object may be used but only in limited ways. <...> if the original object will be or was
of a non-POD class type, the program has undefined behavior if:
— the lvalue is used to <...> call a non-static member function of the object


M> Во-первых — оба времени жизни оговариваются стандартом,


Только одно из этих времен стандарт называет временем жизни, для второго используется
термин storage duration.

M> область памяти то прекрасно продолжает жить и никуда не девается!

M> Более того, стандарт так же чётко оговаривает её время жизни.

Т.е. storage duration.

M> И общий смысл замысловатых правил таков — она продолжает относится к объекту

M> — пока не освобождена и отдана системе <...>

Снова твои фантазии: стандарт ничего подобного не гарантирует.

M> Теперь рассмотрим, что такое "нетривиальный" деструктор <...> Рассмотрим объект,

M> который в начале своей работы резервирует динамическую память <...> Деструктор
M> освободит все эти объекты и память. <...> Вот как раз мы и получили
M> пример объекта с "нетривиальным" деструктором.

Ерунда. Стандарт дает четкое определение тривиального деструктора, приведенное выше.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.