首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

new[]得到的内存居然不能delete[],WHY,代码比较多,有心者进。该如何解决

2012-02-26 
new[]得到的内存居然不能delete[],WHY,代码比较多,有心者进。new[]得到的内存居然不能delete[],WHY,代码比

new[]得到的内存居然不能delete[],WHY,代码比较多,有心者进。
new[]得到的内存居然不能delete[],WHY,代码比较多,有心者进。
《提高C++性能的编程技术》一书源代码中,固定大小对象的内存池,有误,百思不得其解,最终的改正却运行成功,但还是不解。
三个源文件:
//MemoryPool.h
#ifndef   MEMORYPOOL_H_
#define   MEMORYPOOL_H_

template <class   T>
class   MemoryPool
{
private:
        MemoryPool <T> *   next;
        enum   {EXPANSION_SIZE   =   32};
        void   expandTheFreeList(int   howMany   =   EXPANSION_SIZE);
public:
        MemoryPool(size_t   size   =   EXPANSION_SIZE);
        ~MemoryPool();
        inline   void*   alloc(size_t   size);
        inline   void   free(void*   doomed);
};
template <class   T>
MemoryPool <T> ::MemoryPool(size_t   size)
{
        expandTheFreeList(size);
}
template <class   T>
MemoryPool <T> ::~MemoryPool()
{
        MemoryPool <T> *   nextPtr   =   next;
delete   nextPtr;//此处为我修改代码,代替下面的注释代码才可运行。

    //     for   (nextPtr   =   next;   nextPtr   !=   NULL;   nextPtr   =   next)
    //     {
    //             next   =   next-> next;
    //             delete   []   nextPtr;
////delete   nextPtr;
    //     }
}
template <class   T>
inline
void*   MemoryPool <T> ::alloc(size_t   size)
{
        if   (!next)
                expandTheFreeList();
        MemoryPool <T> *   head   =   next;
        next   =   head-> next;
        return   head;
}
template <class   T>
inline
void   MemoryPool <T> ::free(void*   doomed)
{
        MemoryPool <T> *   head   =   static_cast <MemoryPool <T> *   > (doomed);
        head-> next   =   next;
        next   =   head;
}
template <class   T>
inline
void   MemoryPool <T> ::expandTheFreeList(int   howMany)
{
        size_t   size   =   (sizeof   (T)   >   sizeof   (MemoryPool <T> *))   ?
                                    sizeof   (T)   :   sizeof   (MemoryPool <T> *);
        MemoryPool <T> *   runner   =   static_cast <MemoryPool <T> *   > ((void*)new   char[size]);
        next   =   runner;
        for   (int   i   =   0;   i   <   howMany;   i++)
        {
                runner-> next   =   static_cast <MemoryPool <T> *   > ((void*)new   char[size]);
                runner   =   runner-> next;


        }
        runner-> next   =   0;
}
#endif   //   MEMORYPOOL_H_
//Rational.h
#ifndef   RATIONAL_H_
#define   RATIONAL_H_
#include   "MemoryPool.h "
class   Rational
{
private:
int   n;
int   d;
        static   MemoryPool <Rational> *   memPool;
public:
Rational(int   a   =   0,   int   b   =   1)   :   n(a),   d(b)   {}
~Rational()   {}
void*   operator   new(size_t   size)
{
        return   memPool-> alloc(size);
}
void   operator   delete(void*   doomed,   size_t   size)
{
        memPool-> free(doomed);
}
static   void   newMemPool()
{
        memPool   =   new   MemoryPool <Rational> ;
}
static   void   deleteMemPool()
{
        delete   memPool;
}

};


#endif   //   RATIONAL_H_

//testRationalv2.cpp
#include   <iostream>
#include   <ctime>
#include   "Rational.h "

using   namespace   std;

MemoryPool <Rational> *   Rational::memPool   =   0;
int   main()
{
        clock_t   start,   finish;
        double   dif;
        Rational*   array[1000];
        Rational::newMemPool();
        //计时开始
        start   =   clock();
        for   (int   j   =   0;   j   <   500;   j++)
        {
        for   (int   i   =   0;   i   <   1000;   i++)
        {
        array[i]   =   new   Rational(i);
        }
        for   (int   i   =   0;   i   <   1000;   i++)
        {
        delete   array[i];
        }
        }
        //计时结束
        finish   =   clock();
        Rational::deleteMemPool();

        dif   =   (double)(finish   -   start);
        cout   < <   "processor   time   "   < <   dif   < <   endl;

        system( "PAUSE ");
        return   0;
}

问题处在MemoryPool的析构函数中,内存都是通过new[]申请得来的,书上的源代码也是用delete[]释放,但是却编译不成功,不信你可以试试,然而我改成delete释放却可以了,不知道产生了内存泄漏没有。
麻烦各位赐教。

[解决办法]
你申请的是只是char数组可以直接用delete释放
[解决办法]
MemoryPool <T> * runner = static_cast <MemoryPool <T> * > ((void*)new char[size]);
你说的是这个吧。你认为它是new []出来的。
那,你delete的时候,指针类型和new的时候相同吗?
delete [] (char *)XXX;


当然,于是你又漏了一个MemoryPool <T> * 的析构函数调用问题。
建议你先找 <Effective C++> 看一下重载new/delete的技术要点后,再研究这个。
效率和语法的直观/简洁是冲突的。建议你不要试图抠这一点点效率,几乎没有项目需要这一点点效率。
关于优化的建议就是:
第一:不要优化
第二:(仅供专家,)不要优化。
[解决办法]
唯一的关键就是你如何申请的,就如何释放。
所以应该象taodm所说,用 delete [] (char *)nextPtr; 就可以了。
至于因此没有调用析构函数,不必担心,因为你的for循环已经完成了所有内存的释放,无须再调析构函数了。
你改的那种用delete,其实是递归地调用析构函数,虽然每个都释放了,但是是按照MemoryPool <T> 的标准释放的,所以不能保证释放干净的。(如编译器内部用于保存new[]信息的部分没有释放)。因此,用new[],就一定用delete[],并且类型一致就好了。

至于说不要优化,不能认同这种观点。这是因噎废食,对于这种大规模使用堆内存的情况,不用内存池是不可想象的(要知道new在内核中运行,其运行时间是一个加法的1000倍,而最简单的栈分配只要一个加法就可以了,当你不得不大量使用堆时,你是忍受1000倍的速度损失,还是用可以分摊时间的内存池呢?)同时,这个问题和线程安全也没有关系,因为内存池也是用new/delete分配的。
一个前提是,必须知道,优化意味着难度和复杂度,可能比想象中更难,需要更全面地考虑问题。是否有必要付出这个代价呢?有必要时就要付出。
[解决办法]
Vitin(卫亭)同志已经表达的很明确了,没啥可补充的,呵呵。

热点排行