Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » *Теория* | C++ | Самоубийство класса

Ответить
Настройки темы
*Теория* | C++ | Самоубийство класса
pva pva вне форума

Аватара для pva

Ветеран


Сообщения: 1180
Благодарности: 279

Профиль | Отправить PM | Цитировать


Есть два класса (С++) A и B (производные от одного и того же, например), которые нужно использовать по-очереди (они отражают внутреннее состояние другого большого объекта). По некоторому сигналу void A::foo() нужно, чтобы класс A уничтожился, а вместо него создался класс B. Какие будут предложения? Можно немного видоизменять задачу, но чтобы суть оставалась.

Отправлено: 12:56, 31-10-2005

 

редкий гость


Сообщения: 1696
Благодарности: 44

Профиль | Сайт | Отправить PM | Цитировать


pva
Сделать враппер? По-моему, самое логичное решение. Т.е. для пользователя это один объект нкжного интерфейса, а внутри он переадресовывает все вызовы требуемому объекту. Просто и надёжно.

Второй вариант, если на объектр хранится всего один указатель (например как поле какого-то объекта), то можно, например, при создании этого обхекта дать ему указатель на этот указатель, и когда он пожелавет заменить себя на B, пусть просто удалиться, а по указателю запишет адрес ново-созданного B. Просто и очень ненадёжно.

Вариант третий, написать свой аллокатор (или перегрузить operator new/delete), что бы он выделял памяти достаточно под объекты как типа A, так и типа B. Тогда при необходимости удалиться можно вызвать на себя деструктор, и на своём же старом месте с помощью placement new создать объект класса B. По идее, если объекты наследуют одинаковые интерфейсы (лучше если в одинаковом порядке), то будет работать. Сложно, да и нафиг нужно.

-------
http://ivank.ru


Отправлено: 19:40, 31-10-2005 | #2



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

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

pva pva вне форума Автор темы

Аватара для pva

Ветеран


Сообщения: 1180
Благодарности: 279

Профиль | Отправить PM | Цитировать


Вопрос не в этом. Дело в том, что операция delete this вообще говоря противоречит смыслу. Перед вызовом деструктора объект уже не живёт, а его указатель используется, да ещё и виртуальной функцией.
использовать код вроде switch(action) {...} не хочется, т.к. объекты хранят разную информацию.
Код: Выделить весь код
class X {}
class A : X {int n;virtual void foo();}
class B : X {double f;}

std::auto_ptr<X> px(new A());

void A::foo()
{
   // пожелал заменить себя 
   // стандартный аллокатор ::new выделит достаточно памяти
   px.reset(new B());
    // A уже не существует, но используется его указатель
    // например: ++n; по идее здесь access violation
}

Отправлено: 10:39, 03-11-2005 | #3


редкий гость


Сообщения: 1696
Благодарности: 44

Профиль | Сайт | Отправить PM | Цитировать


Цитата:
Дело в том, что операция delete this вообще говоря противоречит смыслу.
Ни в коей мере. Стандартный трюк в COM, например - когда на нас исчерпались внешние ссылки, то убиваем себя (в функции Release).

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

В общем, не вижу противоречий.

-------
http://ivank.ru


Отправлено: 20:56, 03-11-2005 | #4

pva pva вне форума Автор темы

Аватара для pva

Ветеран


Сообщения: 1180
Благодарности: 279

Профиль | Отправить PM | Цитировать


Так что делать? Прослеживать, чтобы A::foo() запускалась только там, где можно?

Отправлено: 13:21, 07-11-2005 | #5

pva pva вне форума Автор темы

Аватара для pva

Ветеран


Сообщения: 1180
Благодарности: 279

Профиль | Отправить PM | Цитировать


Решил через очередь заданий

Отправлено: 10:20, 14-11-2005 | #6


редкий гость


Сообщения: 1696
Благодарности: 44

Профиль | Сайт | Отправить PM | Цитировать


pva
Пардон, потерял тему, поэтому не отвечал. Как я уже сказал, я бы обернул вызовы методов A и B во враппер AB, который внутри вызвает методы соответствующего объекта. Опять же так и внешние ссылки отследить проще.

Цитата:
Решил через очередь заданий
Не пояснишь, что такое очередь заданий?

-------
http://ivank.ru


Отправлено: 18:45, 14-11-2005 | #7

pva pva вне форума Автор темы

Аватара для pva

Ветеран


Сообщения: 1180
Благодарности: 279

Профиль | Отправить PM | Цитировать


Можно код? Я не понял.

Очередь заданий:
Код: Выделить весь код
// класс задание или действие
class TAction
{
public: 
     virtual ~TAction() {}
     virtual void fire() = 0;
};

// список заданий (exception-safe)
class TActionList
{
    typedef std::vector<TAction*>::iterator iter;
    std::vector<TAction*> fitems;

    void _remove(iter a, iter b)
    {
         for(iter c=a; a!=b; ++c) delete *c;
         fitems.erase(a,b);
    }

public:
   ~TActionList() {clear();}
   void add(TAction* a) {fitems.push_back(a);}
   void remove(TAction* a) {_remove(std::remove(fitems.begin(), fitems.end(), a));}
   void clear() {_remove(fitems.begin(), fitems.end());}
   void fire() {for(iter a=fitems.begin(), b=fitems.end(); a!=b; ++b) (*a)->fire();}
};

// класс, управляющий жизнью объектов
// TObject::execute() можно вызывать только один раз при запуске программы
class TObject
{
    static TActionList fcleanup;
    static void processTasks();
    static void cleanup() {fcleanup.fire(); fcleanup.clear();}
public:
    static void execute();
    static void registerCleanup(TAction* a) {fcleanup.add(a);}
}

TActionList TObject::fcleanup;

void TObject::execute()
{
     while (waitTask())
    {
           processTasks();  // каким-нибудь образом вызывает A::foo();
           cleanup();   // такой доступ к cleanup() гарантирует, что в стеке ничего от A:: не запущено
    }
}

...
// где-нибудь в программе:
std::auto_ptr<A> behavior;

void A::foo()
{
     struct cleanup_A
     {
           void fire() { clog << "cleanup_A" << end;}
           cleanup_A(A* a) : fcleanup(a);
      private:
           std::auto_ptr<A> fcleanup;
     }

     std::auto_ptr<A> b(new B(...));
     std::auto_ptr<cleanup_A> clean_a(new cleanup_A(behavior.get()));
     TObject::registerCleanup(clean_a.get());

     clean_a.release();   // non-throwing
     behavior.release();  // non-throwing
     behavior = b;           // non-throwing
}
Эффект кода подобен чистильщику java, только чистит когда делать нечего, а не когда память кончилась
Для полной картины, хорошо бы добавить A::unlink(), которая убирает связи ещё живого A с другими объектами.

Отправлено: 13:11, 16-11-2005 | #8



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » *Теория* | C++ | Самоубийство класса

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
.NET - Нужны 2 класса на С# срочно. Smile Программирование и базы данных 3 14-01-2010 09:18
ПК класса «all-in-one»: оправдались ли ожидания? OSZone News Новости информационных технологий 0 29-09-2009 02:30
Сеть класса С. Вопросец... clin Microsoft Windows NT/2000/2003 8 07-09-2009 09:36
Разное - [решено] регистрация класса Shadow76 Microsoft Windows 2000/XP 6 04-06-2009 13:55
* Теория * | C++ Доступ к членам класса через указатели Kincajou Программирование и базы данных 6 30-07-2006 22:36




 
Переход