Russian Qt Forum
Сентябрь 29, 2024, 12:36 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 ... 6 7 [8] 9 10   Вниз
  Печать  
Автор Тема: Основы удаления объектов  (Прочитано 85162 раз)
ilot
Гость
« Ответ #105 : Январь 10, 2010, 07:43 »

Ваш пример совершенно не демонстрирует возможности виртуального деструктора. Если заменить его на невиртуальный - результат будет тот же.
Абсолютно точно! Я и не говорил, что этот пример должен демонстрировать работу виртуального деструктора. Я привел примеры классов с виртуальным деструктором, количество new/delete в которых совпадает, и возможность существования которых вы отрицали.
А вот мой самый первый пример с Foo (к которому у вас большие претензии) как раз наглядно демонстрирует работу виртуального деструктора.

Я уже не знаю как проще обьяснить. Ваш пример совершенно не демонстрирует возможности виртуального деструктора.
Напишите свой пример, демонстрирующий его возможности Подмигивающий
Записан
Dendy
Гость
« Ответ #106 : Январь 10, 2010, 09:02 »

Я и не говорил, что этот пример должен демонстрировать работу виртуального деструктора.

Это говорил я, ставя условия задачи. Вы так хорошо рассказывали как работает виртуальный деструктор, а на практике не можете привести пример, где его стоит использовать. Если за вас пример напишу я - вы попросу скажете, что это частный случай, который я подогнал под себя. Я же говорю, что других случаев просто небывает. Чтобы это оспорить - вы должны написать пример сами.
Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #107 : Январь 10, 2010, 09:49 »

Dendy, пиши ТЗ на пример, чёткое не двусмысленное. Чтобы в одном сообщение было только оно и ничего больше, ни каких обсуждений.
Записан

Юра.
Dendy
Гость
« Ответ #108 : Январь 10, 2010, 10:25 »

Написать пример, в котором:

а) демонстрируется использование виртуального деструктора в классе;
б) количество new/delete в коде для этого класса (или его наследников) совпадало.
Записан
BigZ
Гость
« Ответ #109 : Январь 10, 2010, 11:44 »

Написать пример, в котором:

а) демонстрируется использование виртуального деструктора в классе;
б) количество new/delete в коде для этого класса (или его наследников) совпадало.
Вам уже писали такой пример:

class Foo: public QObject{
   enum{size = 100};
   int* m_data;
public:
   Foo(QObject* pobj = 0):QObject(pobj){
      m_data = new int[size];
   }
   ~Foo(){
      delete []m_data;
      std::cout << "Foo destructor" << std::endl;
   }
};
int main(int argc, char *argv[])
{
   QObject* pobj = new Foo;
   //do something...
   delete pobj;//вызывается деструктор Foo
}
Записан
Dendy
Гость
« Ответ #110 : Январь 10, 2010, 11:53 »

BigZ, прочитайте весь тред. Выше я уже указал, что пример не демонстрирует смыл виртуального деструктора, поскольку нет ни одной причины хранить указать на экземпляр Foo в QObject*, а не в Foo*. Вопрос не в теории как оно работает, а в реальной задаче, которую виртуальный деструктор призван выполнять.
Записан
BigZ
Гость
« Ответ #111 : Январь 10, 2010, 12:00 »

Да, я прочитал конечно. Пример отлично демонстрирует возможности виртуального деструктора. Как считаешь ~Foo() в данном примере виртуальный или нет?
Записан
Dendy
Гость
« Ответ #112 : Январь 10, 2010, 12:19 »

Когда я сказал:
пример не демонстрирует смыл виртуального деструктора
то указал почему:
поскольку нет ни одной причины хранить указать на экземпляр Foo в QObject*, а не в Foo*

Ваши же слова лишены аргументов:
Пример отлично демонстрирует возможности виртуального деструктора.
Записан
BigZ
Гость
« Ответ #113 : Январь 10, 2010, 12:28 »

поскольку нет ни одной причины хранить указать на экземпляр Foo в QObject*, а не в Foo*
Причина есть и существенная, продемонстрировать возможности виртуального деструктора.

Ваши же слова лишены аргументов:
>>Пример отлично демонстрирует возможности виртуального деструктора.
Чтобы эти слова стали аргументом нужен ответ на мой вопрос - ~Foo() в данном примере виртуальный или нет и почему?
Записан
Dendy
Гость
« Ответ #114 : Январь 10, 2010, 12:45 »

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

- Грузины лучше, чем армяне.
- Чем?
- Чем армяне.

Демонстрация возможности призвана показать, как данный приём позволяет решить задачу, которую невозможно решить другим способом. В даном случае смысл в виртуальном деструктора отсутствует, поскольку если его убрать - задача решается точно так же, заменой QObject* на Foo*. Попробуйте обьяснить новичку зачем Страуструп придумал виртуальные деструкторы, когда задача выполняется простой заменой QObject* на Foo*. Этот пример не показывает ничего, придумайте другой.
Записан
BigZ
Гость
« Ответ #115 : Январь 10, 2010, 12:52 »

class Foo: public QObject{
   enum{size = 100};
   int* m_data;
public:
   Foo(QObject* pobj = 0):QObject(pobj){
      m_data = new int[size];
   }
   ~Foo(){
      delete []m_data;
      std::cout << "Foo destructor" << std::endl;
   }
};

void deleteQObject(QObject* pobj)
{
   delete pobj;//вызывается деструктор Foo
}

int main(int argc, char *argv[])
{
   Foo* pobj = new Foo;
   //do something...
   deleteQObject(pobj);
}

Хм... так понятнее?
Записан
Dendy
Гость
« Ответ #116 : Январь 10, 2010, 12:59 »

Новичёк задаёт резонный вопрос: почему deleteQObject принимает указатель на QObject, а не на Foo? И ещё он спраишвает, зачем вообще нужен метод deleteQObject, если то же самое можно сделать, вызвав просто delete?

Очевидно, вы так и не поняли. Я не прошу любой код с виртуальным деструктором. Я прошу показать задачу, которую он призван выполнять. Задачу, которую иначе решить нельзя. Задачу, в которой виртуальный деструктор необходим.
« Последнее редактирование: Январь 10, 2010, 13:02 от Dendy » Записан
BigZ
Гость
« Ответ #117 : Январь 10, 2010, 13:07 »

class Foo: public QObject{
public:
   Foo(QObject* pobj = 0) {}
   ~Foo(){}
};

class Foo2: public QObject{
public:
   Foo2(QObject* pobj = 0) {}
   ~Foo2(){}
};

void deleteQObject(QObject* pobj)
{
#ifdef DEBUG
   static int destroyCallsCount = 0;
   destroyCallsCount++;
#endif
   delete pobj;//вызывается деструктор объекта наследованного от QObject
}

int main(int argc, char *argv[])
{
   Foo* pobj = new Foo;
   Foo2* pobj2 = new Foo2;

   //do something...
   deleteQObject(pobj);
   deleteQObject(pobj2);
}

Теперь понятно какую задачу решает deleteQObject, почему он принимает в качестве параметра QObject а не Foo, и где в этом примере используется виртуальный деструктор?
« Последнее редактирование: Январь 10, 2010, 13:10 от BigZ » Записан
Dendy
Гость
« Ответ #118 : Январь 10, 2010, 13:10 »

Отличный пример, спасибо. То что я ожидал увидеть. Как видим - 2 new, 1 delete, что и требовалось доказать.
Записан
ilot
Гость
« Ответ #119 : Январь 10, 2010, 13:15 »

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

Написать пример, в котором:

а) демонстрируется использование виртуального деструктора в классе;
б) количество new/delete в коде для этого класса (или его наследников) совпадало.
В демонстрационных целях разрабатывается простой контейнер Stack.

Проблема состоит в следующем: нужно чтобы в контейнере Stack можно было хранить объекты разных типов, но при этом не использовать указатели на void. Одно из возможных решений - шаблоны. С целью демонстрации работы виртуального деструктора реализуется подход, основанный на полиморфизме. В рассматриваемом далее решении используется так называемая однокоренная иерархия. Чтобы решить проблему типизации объектов, мы создаем чрезвычайно простой базовый класс Object, содержащий виртуальный деструктор. Далее в контейнере Stack сохраняются указатели на объекты классов, производных от Object, демонстрируется работа с ними через общий интерфейс. В приводимом примере корректная зачистка памяти возможна только при наличии виртуального деструктора.

Господа, можете начинать подсчитывать количество new/delete в исходном коде, сама возможность существования которого опровергалась. Улыбающийся

Код:
//Stack.h
#ifndef STACK_H
#define STACK_H

#include "ObjectsHierarchy.h"

class Stack{
struct Node{
Object* data;
Node* next;
Node(Object* _data, Node* _next): data(_data), next(_next){}
}* top;
public:
Stack():top(0){}
~Stack(){
//контейнер Stack не является владельцем объектов типа Object - за их создание и удаление
//отвечает код, использующий экземпляр класса Stack. Удаляются только узлы Node
while(top) pop();
}
void push(Object* _data){
top = new Node(_data, top);
}
Object* peek() const{
return (top ? top->data : 0);
}
Object* pop(){
if(top == 0) return 0;
Object* result = top->data;
Node* oldTop = top;
top = top->next;
delete oldTop;
return result;
}
};

#endif //STACK_H

//ObjectsHierarchy.h
#ifndef OBJECT_HIERARCHY_H
#define OBJECT_HIERARCHY_H

#include <iostream>

typedef unsigned char byte;
typedef unsigned int uint;
const unsigned int default_size = 100;

class Object{
public:
Object(){}
virtual ~Object(){
std::cout<< "Object destructor" << std::endl;
}
virtual char* presentation() = 0;
};

class Derived1: public Object{
byte *m_data;
public:
Derived1(uint size = default_size): Object(){
m_data = new byte[size];
}
virtual ~Derived1(){
delete []m_data;
std::cout << "Derived1 destructor" << std::endl;
}
char* presentation(){return "I'm class Derived1";}
static Derived1* create(uint size = default_size){
return new Derived1(size);
}
void remove(){
delete this;
}
};

class Derived2: public Object{
byte *m_data;
public:
Derived2(uint size = default_size): Object(){
m_data = new byte[size];
}
virtual ~Derived2(){
delete []m_data;
std::cout << "Derived2 destructor" << std::endl;
}
char* presentation(){return "I'm class Derived2";}
static Derived2* create(uint size = default_size){
return new Derived2(size);
}
void remove(){
delete this;
}
};
#endif //OBJECT_HIERARCHY_H

//main.cpp

#include <iostream>
#include "Stack.h"
#include "ObjectsHierarchy.h"

int main(){
Stack st;
//заполняем контейнер разнородными объектами
for(uint i = 0; i < 5; i++){
st.push(Derived1::create(i*10));
}
for(uint i = 5; i < 10; i++){
st.push(Derived2::create(i*10));
}
st.push(new Derived1(1000));//до кучи
Object* p = 0;
while(p = st.pop()){
//унифицированно работаем с объектами через их общий интерфейс
std::cout << p->presentation() << std::endl;
//удаляем больше не нужные объекты
delete p;//работает виртуальный деструктор
}

return 0;
}
Записан
Страниц: 1 ... 6 7 [8] 9 10   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.054 секунд. Запросов: 23.