为延迟事件参数分配内存

时间:2010-10-15 18:00:40

标签: c++ memory-management

这是我的问题。 我有一个类来创建定时事件。它需要:

void (*func)(void* arg)

的函数指针

参数的void*

延迟

问题是我可能想创建我不希望成为类中的静态变量的动态变量,或全局变量。如果不满足其中任何一个,我就不能这样做:

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

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

这不起作用,因为当函数返回时bool被破坏了。所以我必须在堆上分配这些。然后问题变成了,谁分配谁删除。我想做的是能够接收任何东西,然后复制它的内存并在定时事件类中管理它。但我不认为我可以做memcpy,因为我不知道这个问题。

在时间事件负责内存管理的情况下,实现这一目标的好方法。

由于

我不使用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 个答案:

答案 0 :(得分:1)

为什么不使用boost::shared_ptr

它提供了您需要的存储持续时间,因为只有当指向它的所有shared_ptrs都被破坏时,底层对象才会被破坏。

它还提供完整的线程安全性。

答案 1 :(得分:1)

使用C ++ 0x unique_ptr非常适合这项工作。这是未来的标准,但G ++和Visual Studio已经支持unique_ptr。对于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。

答案 2 :(得分:0)

如果你不能使用boost或tr1,那么我要做的就是编写我自己的函数,其行为类似于auto_ptr。事实上,这就是我在这里没有任何提升或tr1访问的项目所做的。当所有关心数据的事件都完成后,它会自动被删除。

答案 3 :(得分:0)

您可以只更改函数定义以获取一个额外的参数,该参数表示传入的对象的大小。然后只需传递大小。所以你的新函数声明如下所示:

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); 
}

然后,您可以传递仍在堆栈中的变量,并在定时事件类中记忆它们。唯一的问题是你不再知道这种类型......但是当你转向虚空时会发生什么*

希望有所帮助。

答案 4 :(得分:0)

您应该重新使用您的类来使用继承,而不是函数指针。

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
}