Выделение памяти для аргументов отложенного события - PullRequest
0 голосов
/ 15 октября 2010

Вот моя проблема. У меня есть класс для создания временных событий. Требуется:

Указатель функции void (*func)(void* arg)

A void* до аргумента

Задержка

Проблема в том, что я могу захотеть создать переменные «на лету», которые я не хочу, чтобы они были статической переменной в классе или глобальной переменной. Если ни один из них не выполняется, я не могу сделать что-то вроде:

void doStuff(void *arg)
{
   somebool = *(bool*)arg;
}

void makeIt()
{
bool a = true;
   container->createTimedEvent(doStuff,(void*)&a,5); 
}

Это не сработает, потому что bool уничтожается при возврате функции. Так что мне придется распределить их по куче. Тогда возникает вопрос, кто распределяет, а кто удаляет. то, что я хотел бы сделать, - это иметь возможность воспринимать что-либо, затем копировать его память и управлять им в классе временных событий. Но я не думаю, что смогу сделать memcpy, так как я не знаю tyoe.

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

Спасибо

Я не использую Boost

class AguiTimedEvent {
    void (*onEvent)(void* arg);
    void* argument;
    AguiWidgetBase* caller;
    double timeStamp;
public:
    void call() const;

    bool expired() const;
    AguiWidgetBase* getCaller() const;
    AguiTimedEvent();
    AguiTimedEvent(void(*Timefunc)(void* arg),void* arg, double timeSec, AguiWidgetBase* caller);
};

void AguiWidgetContainer::handleTimedEvents()
{
    for(std::vector<AguiTimedEvent>::iterator it = timedEvents.begin(); it != timedEvents.end();)
    {
        if(it->expired())
        {

            it->call();
            it = timedEvents.erase(it);
        }
        else
            it++;
    }
}

void AguiWidgetBase::createTimedEvent( void (*func)(void* data),void* data,double timeInSec )
{
    if(!getWidgetContainer())
        return;
    getWidgetContainer()->addTimedEvent(AguiTimedEvent(func,data,timeInSec,this));
}


void AguiWidgetContainer::addTimedEvent( const AguiTimedEvent &timedEvent )
{
    timedEvents.push_back(timedEvent);
}

Ответы [ 5 ]

1 голос
/ 15 октября 2010

Использование C ++ 0x unique_ptr идеально подходит для работы. Это будущий стандарт, но unique_ptr уже поддерживается в G ++ и Visual Studio. Для C ++ 98 (текущий стандарт) auto_ptr работает как сложная в использовании версия unique_ptr ... Для C ++ TR1 (реализовано в Visual Studio и G ++) вы можете использовать std :: tr1 :: shared_ptr.

По сути, вам нужен умный указатель. Вот как будет работать unique_ptr:

unique_ptr<bool> makeIt(){ // More commonly, called a "source"
    bool a = true;
    container->createTimedEvent(doStuff,(void*)&a,5); 
    return new unique_ptr<bool>(a)
}

При последующем использовании кода ...

void someFunction(){
    unique_ptr<bool> stuff = makeIt();
} // stuff is deleted here, because unique_ptr deletes 
  // things when they leave their scope

Вы также можете использовать его как функцию «Мойка»

  void sink(unique_ptr<bool> ptr){
    // Use the pointer somehow
  }

  void somewhereElse(){
      unique_ptr<bool> stuff = makeIt();
      sink(stuff);
      // stuff is now deleted! Stuff points to null now
  }

Кроме этого, вы можете использовать unique_ptr как обычный указатель, кроме странных правил движения. Есть много умных указателей, unique_ptr - только один из них. shared_ptr реализован в Visual Studio и G ++ и является более типичным ptr. Однако мне лично нравится использовать unique_ptr как можно чаще.

1 голос
/ 15 октября 2010

Почему бы вам не использовать boost::shared_ptr?

Он предлагает необходимую вам продолжительность хранения, поскольку базовый объект будет уничтожен только тогда, когда будут уничтожены все указывающие на него shared_ptrs.1006 *

Также предлагает полную безопасность потока.

0 голосов
/ 15 октября 2010

Вам следует переделать ваш класс, чтобы использовать наследование, а не указатель на функцию.

class AguiEvent {
    virtual void Call() = 0;
    virtual ~AguiEvent() {}
};

class AguiTimedEvent {
    std::auto_ptr<AguiEvent> event;
    double timeSec;
    AguiWidgetBase* caller;
public:
    AguiTimedEvent(std::auto_ptr<AguiEvent> ev, double time, AguiWidgetBase* base)
        : event(ev)
        , timeSec(time)
        , caller(base) {}
    void call() { event->Call(); }

    // All the rest of it
};

void MakeIt() {
    class someclass : AguiEvent {
        bool MahBool;
    public:
        someclass() { MahBool = false; }
        void Call() { 
            // access to MahBool through this.
        }
    };
    something->somefunc(AguiTimedEvent(new someclass())); // problem solved
}
0 голосов
/ 15 октября 2010

Вы можете просто изменить определение своей функции, чтобы получить дополнительный параметр, который представляет размер передаваемого объекта. Затем просто передайте размер вниз. Итак, ваши новые объявления функций выглядят так:

void (*func)(void* arg, size_t size)

void doStuff(void *arg, size_t size)
{
   somebool = *(bool*)arg;
   memcpy( arg, myStorage, size );
}


void makeIt()
{
   bool a = true;
   container->createTimedEvent(doStuff,(void*)&a,sizeof(bool), 5); 
}

Затем вы можете передать переменные, которые все еще находятся в стеке, и записать их в класс событий по времени. Единственная проблема в том, что вы больше не знаете тип ... но это то, что происходит, когда вы разыгрываете void *

Надеюсь, это поможет.

0 голосов
/ 15 октября 2010

Если вы не можете использовать boost или tr1, то я бы написал свою собственную функцию, которая ведет себя как auto_ptr.Фактически, это то, что я сделал в проекте, который не имеет никакого повышения или доступа tr1.Когда все события, связанные с данными, завершаются, они автоматически удаляются.

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