1. 我在写一个程序使用内存分配(自己写的类是在类构造时分配空间),分配时没错,可是释放(是在类析构时)就出错。我把析构时的代码去掉就没事了,是怎么回事那?难道分配的内存不用释放?
我用的是win2000,编译环境是VC6.0。
局部代码如下:
template <class Type>
CSqList<Type>::CSqList(void)
{
    //elem是一个Type类型的指针,是个私有变量
    elem=(Type *)malloc(LIST_INIT_SIZE*sizeof(Type));
    if(!elem) 
    {
        MessageBox(NULL,"内存不足!!!","程序错误",MB_OK);
    }
    ListSize=LIST_INIT_SIZE;
    Length=0;
    IsSort=0;
}template <class Type>
CSqList<Type>::~CSqList()
{
        //free(elem);
}+重载如下:
template <class Type>
CSqList<Type> CSqList<Type>::operator+(CSqList &B) //+运算符操作
{
    int Len;
    Len=Length+B.Length;
    CSqList temp(Len);
    memcpy(temp.elem,elem,Length*sizeof(Type));
    memcpy(&(temp.elem[Length]),B.elem,B.Length*sizeof(Type));
    temp.Length=Len;    return temp;
}比如运行a=a+b时,它调用了析构函数,然后就出错了!怎么回事?2. new和malloc有什么区别,他们具体是怎么实现的?
3. 内存的分配是不是和所用的操作系统有关,希望详解。

解决方案 »

  1.   

    new 和 malloc 都是动态分配内存的有效手段,
    他们最大的不同大概就是在于new能完成动态内存分配和初始化工作
    delete 能完成清理与释放内存工作
    malloc/free是库函数而不是运算符,不在编译器控制权限之内
    不能执行构造函数与析构函数
    创建动态对象时区别比较明显
    内存的分配当然和所用的操作系统有关,在win2000下一般不会出现
    因为系统内存分配而导致的错误
    至于你的问题,把free()移到构造函数中试试吧
      

  2.   

    +重载如下:
    template <class Type>
    CSqList<Type> CSqList<Type>::operator+(CSqList &B) //+运算符操作
    {
        int Len;
        Len=Length+B.Length;
        CSqList temp(Len);
        memcpy(temp.elem,elem,Length*sizeof(Type));
        memcpy(&(temp.elem[Length]),B.elem,B.Length*sizeof(Type));
        temp.Length=Len;    return temp;
    }——你的代码有问题:
    你在函数中定义了一个临时对象:
    CSqList temp(Len);
    并返回它的值:
    return temp;函数采取的值返回:
    CSqList<Type>.....这样,在返回时,编译器会生成一个临时对象,并用你的临时对象来初始化它:
    CSqList functemp = temp;
    ....由于你没有定义"="操作符,因此编译器会对成员变量进行值拷贝,编译器生成的临时对象的elem成员就直接复制过去了。实验室要关门了,就写这么多了
    反正,你还要重载"="操作符!在其中对elem进行必要操作。
    好运....^_^
      

  3.   

    阿,没有对“=”进行操作符重载的话就是浅复制
    学习学习ing
      

  4.   

    common_man(谢安王导)的解释已经很明了,解决方法是重载“=” 或加一个复制构造函数。关键是动态分配的内存,在新的实例中要自己分配,否则如果,A=B,A的elem没有自己分配内存,而是指向B的elem,B析构时销毁了自己的elem,A的elem就指向错误的内存了。
      

  5.   

    问题不止这儿。你在生成临时变量时也分配了内存,其指针也指向有效内存,但指针值在memcpy时被覆盖了,这样那块内存被泄露了。
    这段程序还有一个缺陷,对于模版类,用malloc是不会调用其构造函数的,所以应该用new和delete。
      

  6.   

    昨天时间紧迫,我没写清楚,这里再写仔细一点:
    你一开始在析构函数中释放了内存:
    template <class Type>
    CSqList<Type>::~CSqList()
    {
            free(elem);
    }
    那么你的重载函数:
    template <class Type>
    CSqList<Type> CSqList<Type>::operator+(CSqList &B) //+运算符操作
    {
        int Len;
        Len=Length+B.Length;
        CSqList temp(Len);
        memcpy(temp.elem,elem,Length*sizeof(Type));
        memcpy(&(temp.elem[Length]),B.elem,B.Length*sizeof(Type));
        temp.Length=Len;    return temp;
    }中的局部变量在出函数体时,其所分配的内存也释放掉了,正如上面所说,由于你没有定义"="操作符,因此编译器会对成员变量进行值拷贝,编译器生成的临时对象的elem成员就直接拷贝你的局部变量的elem成员,导致临时对象的elem成员指向一块已释放的内存,导致错误。
    后来, 你在析构函数中把释放内存的语句注释掉了,因此,编译器生成的临时对象的elem成员直接拷贝你的局部变量的elem成员后,指向的是一块有效内存,因此不会出错,不过,这块内存永远不能回收了。。
    有两个解决办法:
    1。重载"="操作符
    template <class Type>
    CSqList<Type>&  CSqList<Type>::operator=(const CSqList &B) 
    {
        Length=B.Length;
        elem=(Type *)malloc(Length*sizeof(Type));
        memcpy(elem,B.elem,Length*sizeof(Type));    return *this;
    }
    2.改写+重载,改为引用返回:
    template <class Type>&
    CSqList<Type> CSqList<Type>::operator+(CSqList &B) //+运算符操作
    {
        int Len;
        Len=Length+B.Length;
        CSqList *ptemp  = new CSqList(Len);
        memcpy(ptemp->elem,elem,Length*sizeof(Type));
        memcpy(ptemp->elem+Length,B.elem,B.Length*sizeof(Type));
        ptemp->Length=Len;    return *ptemp;
    }
      

  7.   

    还有,你在构造函数中调用malloc来分配内存,如果你的class Type是一个类(比如CString),而不是内置类型(如int,float等),就不会调用该类的构造函数,同理
    ,free也不会调用该类的析构函数,因此,还是建议用new和delete:
    elem=(Type *)malloc(LIST_INIT_SIZE*sizeof(Type));
    改为:
    elem = new Type[LIST_INIT_SIZE]free改为:
    delete[] elem
      

  8.   

    第一个方法还有点问题,应该如下:
    1。重载"="操作符
    template <class Type>
    CSqList<Type>&  CSqList<Type>::operator=(const CSqList &B) 
    {
        free(elem);    //释放掉原来分配的内存
        Length=B.Length;
        elem=(Type *)malloc(Length*sizeof(Type));
        memcpy(elem,B.elem,Length*sizeof(Type));    return *this;
    }
      

  9.   

    common_man(谢安王导) ,
    great responsibility,cheers!
      

  10.   

    谢谢common_man(谢安王导)的全力帮助!!!!!!
    我想问一下,那有关于算符重载的文章,我想看看。
    还有
    template <class Type>& 
    CSqList<Type> CSqList<Type>::operator+(CSqList &B)
    这样写具体实现代码编译不过去,还有函数声明应该怎么写呢?
      

  11.   

    《c++primer》中讲的很详细,你可以看看不好意思,写错了,唉,眼神是越来越差了(引用符号的位置搞错了),应该如下:
    template <class Type>
    CSqList<Type>& CSqList<Type>::operator+(CSqList &B) //+运算符操作
    {
        int Len;
        Len=Length+B.Length;
        CSqList *ptemp  = new CSqList(Len);
        memcpy(ptemp->elem,elem,Length*sizeof(Type));
        memcpy(ptemp->elem+Length,B.elem,B.Length*sizeof(Type));
        ptemp->Length=Len;    return *ptemp;
    }
      

  12.   

    完整声明、定义如下:
    template <class Type>
    class CSqList
    {
    ...
    CSqList&  operator+(const CSqList &B);
    ...
    }template <class Type>
    CSqList<Type>& CSqList<Type>::operator+(const CSqList<Type> &B) //+运算符操作
    {
        int Len;
        Len=Length+B.Length;
        CSqList *ptemp  = new CSqList(Len);
        memcpy(ptemp->elem,elem,Length*sizeof(Type));
        memcpy(ptemp->elem+Length,B.elem,B.Length*sizeof(Type));
        ptemp->Length=Len;    return *ptemp;
    }
      

  13.   

    呵呵,成了!谢谢了!!!
    我想问一下,CSqList *ptemp  = new CSqList(Len)以后,分配的空间释放了吗?
      

  14.   

    CSqList&  operator+(const CSqList &B),为什么参数B你要定义为const CSqList &B?
      

  15.   

    会释放的,比如你有一个函数:
    void fun(...)
    {
    ...
    c = a + b;//a,b,c都是你的类实例
    ...
    }其中的c就是+重载中的下句生成的:
    CSqList *ptemp  = new CSqList(Len);
    在函数执行完了后,c被析构,也就是会调用c的析构函数,其所申请的内存自然被释放了(当然了,你的析构函数要负责释放内存)CSqList&  operator+(const CSqList &B)
    ——const修饰是为了避免在函数体中修改了参数的值。在+重载中,参数b的值是不应该变的,因此我给他加了一个const修饰,这是一种比较好的预警机制
      

  16.   

    是在重载+运算符中建立的CSqList *ptemp  = new CSqList(Len);
    在函数完成时 return *ptemp;
    这样的话应该ptemp这个指针释放了,还是它所指的空间释放了呢?
    像我一开始写的+运算符,在函数结束时局部变量已被释放了,我以为它已经被压入栈中,可是空间已被释放,所以出错,那你这个是怎么回事呢?
    谢谢大侠指点!!! ^_^
      

  17.   

    是在重载+运算符中建立的CSqList *ptemp  = new CSqList(Len);
    在函数完成时 return *ptemp;
    这样的话应该ptemp这个指针释放了,还是它所指的空间释放了呢?
    ——这样写,就是ptemp这个指针被释放了,而他所指的空间并没有被释放你一开始的代码中是这样写的:
    ...
    CSqList temp(Len);
    ...这是在函数的栈空间定义的局部变量,这样,在函数数结束时就会调用局部变量temp的析构函数,你又在析构函数中调用了free,因此,空间就释放掉了而这样写:
    CSqList *ptemp  = new CSqList(Len);
    是在堆上申请的内存,因此在函数结束后不会调用对象的析构函数的
      

  18.   

    那这个空间CSqList *ptemp  = new CSqList(Len)还是没有释放呀,怎么办?
      

  19.   

    我在上面已经说了呀,^_^:
    会释放的,比如你有一个函数:
    void fun(...)
    {
    ...
    c = a + b;//a,b,c都是你的类实例
    ...
    }其中的c就是+重载中的下句生成的:
    CSqList *ptemp  = new CSqList(Len);在fun函数执行完了后,c被析构,也就是会调用c的析构函数,其所申请的内存自然被释放了(当然了,你的析构函数要负责释放内存)
      

  20.   

    哦,这样的话我还是要在~CSqList()中将内存释放掉,可是指向内存地址的指针已被释放了,难道需要建一个量来保存地址?这里怎么解决好呢?
      

  21.   

    不,你的析构函数只要象你一开始那样写就行了:
    template <class Type>
    CSqList<Type>::~CSqList()
    {
            free(elem);
    }
    因为此时elem成员指向的内存就是需要释放的内存
      

  22.   

    不好意思,网络故障一直没法上网,我现在在网吧里上,哈哈!
    我指得是CSqList *ptemp  = new CSqList(Len),这个对象分配的空间的释放,就是new分配的空间的释放。我应在什么地方释放呢?万分感谢common_man同志的指导!!!