c++以Void*释放对象会怎样?

1月24日:
前言:最近在写一个RTMP推流的DEMO,我用的是Message Loop的形式来推流,为了在网络差的时候能够动态丢包,需要在消息队列到达阀值的时候丢掉以前的消息。消息只是个int型,但为了使Message Loop类通用,消息对应的数据是Void,此时动态丢消息就会变成delete Void,当我写这行代码的时候,我惊了,这样真的能释放掉一个Object* 对象?

答案是否。如果直接用delete void,释放空间,这其实和c语言里面的free功能一样,当一个普通指针来释放,只会释放掉void指向的内存,如果void*对象里面还有其他指针,就不能通过析构函数来释放。用一段代码是说明:

class mycalss  
{  
public:  
mycalss() : data(new int[100]){}  
    ~mycalss()  
    {  
        delete[] data;  
    }  
private:  
int *data;  
};  
int main()  
{  
mycalss* pobj =new mycalss;  
delete pobj;  
return 0;  
}  

这里,不会有内存泄漏产生,因为 delete pobj指针的时候,会先调用 myclass 的析构函数释放掉 data*的那块堆内存,然后再释放 sizeof(myclass) 大小的堆内存。如果直接这样用:

int main()  
{  
void* pobj = new mycalss;  
delete pobj;  
return 0;  
}  

这里,会有400字节的内存泄漏,也就是只释放了 sizeof(myclass) 大小的那块堆内存,而pobj->data那块并未被释放,为何?因为析构函数未被调用!!!
所以,请记住,永远不要 delete void,消除所有warning: deleting 'void' is undefined [enabled by default]警告!!!
其实到这里也有一个同样问题,为什么要把父类的析构函数声明成virtual(虚函数)?我这里就不再说明,引用知乎上一个提问。
现在简单说下我最开始遇到的问题。起初,我自然想到share_ptr,但是想了下,这其实和模板一样依然限制里数据类型,看来只能和handle一样写个虚函数,让子类来实现释放代码了。
贴上简短代码:

class looper {
    public:
        looper();
        virtual ~looper();

        //flush 是否清空消息队列
        void post(int what, void *data, bool flush = false);
        void quit();
        virtual void handle(int what, void *data);
    private:
        virtual void addmsg(loopermessage *msg, bool flush);
        static void* trampoline(void* p);
        void loop();
    protected:
        std::deque< loopermessage * > _msgQueue;
        pthread_t worker;
        sem_t headwriteprotect;
        sem_t headdataavailable;
        bool running;
};

这是loop父类,里面消息队列没有限制。

//固定长度loop,超出loop,删除最老消息
  class FixedLoop: public looper
  {
  public:
    FixedLoop(int messageLen);
  private:
   virtual void eraseMsg(int what, void *data);
   virtual void addmsg(loopermessage *msg, bool flush)
  {
    sem_wait(&headwriteprotect);
    if (flush) {
        _msgQueue.clear();
    }
    LOGV("size =%d max =%d",_msgQueue.size(),_MaxMsgLen);
    if(_msgQueue.size() >= _MaxMsgLen)  //移除一个消息
    {
        loopermessage *tempMsg =  _msgQueue.front();
        _msgQueue.pop_front();
        eraseMsg(tempMsg->what,tempMsg->obj);
        delete tempMsg;
    }
    _msgQueue.push_back(msg);
    LOGV("post msg %d", msg->what);
    sem_post(&headwriteprotect);
    sem_post(&headdataavailable);
  }
  private:
   int _MaxMsgLen;
  };

这是固定长度loop子类。

1.29修改:
卧槽,我宛如一个智障,有那么麻烦?不知道数据类型?你不会写一个消息基类,其他的消息都要继承你提供的基类,这样不就可以通过delete基类来释放派生类。突然好鄙视自己,感觉学了这么久c++都白学了,心情无比复杂 ······
2.22:
Loop类源码可以看这篇文章。

你可能感兴趣的:(c++以Void*释放对象会怎样?)