| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 715 人关注过本帖, 1 人收藏
标题:关于析构函数
只看楼主 加入收藏
humy
Rank: 2
等 级:论坛游民
帖 子:69
专家分:18
注 册:2012-7-23
结帖率:92.86%
收藏(1)
已结贴  问题点数:20 回复次数:10 
关于析构函数
书中说:
1“当对象的引用或指针超出作用于时不会运行析构函数,只有删除指向动态内存分配对象的指针或实际对象而非对象的引用超出作用域时才会运行析构函数。 ”我写了下面的例子,是这个意思吗?

{
   int a;
   int* p =&a;
   int &b=a;
   int* c=new int;
}//这里会运行析构函数删除a,c,但不会有析构函数运行删除p,b



   
2" 撤销一个容器,布伦内置数组还是标准库容器,会运行析构函数:
{
  sales_item*p=new sales_item【10】;//我想问这是不是错了不应该sales_item**p吗?
  vector<sales_item> vec(p,p+10);
//...
delete []p;
}
"
按上面的文字,他就会运行析构函数删除数组和容器啊,为什么还要写delete []p;?
搜索更多相关主题的帖子: 动态 
2012-08-23 11:38
lonmaor
Rank: 16Rank: 16Rank: 16Rank: 16
来 自:郑州
等 级:版主
威 望:75
帖 子:2637
专家分:6423
注 册:2007-11-27
收藏
得分:5 
2.通过析构函数删除了之后,占用的内存并没有被释放,只是你访问不到而已。根据c/c++的内存回收机制,动态分配的内存必须手动释放。

从不知道到知道,到知道自己不知道,成长的道路上脚步深深浅浅
2012-08-23 11:54
pangding
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:北京
等 级:贵宾
威 望:94
帖 子:6784
专家分:16751
注 册:2008-12-20
收藏
得分:15 
1“当对象的引用或指针超出作用于时不会运行析构函数,只有删除指向动态内存分配对象的指针或实际对象而非对象的引用超出作用域时才会运行析构函数。 ”我写了下面的例子,是这个意思吗?
是这个意思吧:
程序代码:
#include <iostream>
using namespace std;

class A {
public:
    A() { cout << "A()" << endl; }
    ~A() { cout << "~A()" << endl; }
};

int main()
{
    cout << "main begins" << endl;

    {
        cout << "outer begins" << endl;
        A a;    // 在外层声明A的一个对象。
        A *pa;
        {
            cout << "inner begins" << endl;
            A &p = a;    // 内层引用 A 的一个对象。
            A *qa = new A();    // 内层动态分配的 A。
            pa = qa;
        }
        // 到这,内层的那个引用,和用于动态申请的指针都超出作用域了。但并没有因此引发那两个对象的析构。
        cout << "inner ends" << endl;
        delete pa;    // 删除指向动态内存分配对象的指针才会引发析构。
    }
    // 实际对象 a 超出作用域时引发析构
    cout << "outer ends" << endl;

    cout << "main returns" << endl;

    return 0;
}
上面那个代码的输出是:
main begins
outer begins
A()
inner begins
A()
inner ends
~A()
~A()
outer ends
main returns

2" 撤销一个容器,布伦内置数组还是标准库容器,会运行析构函数: 按上面的文字,他就会运行析构函数删除数组和容器啊,为什么还要写delete []p;?
你那个语法是对的,可以类比: char a[10]; char *p = a;

书可能其实是想说这个意思:
程序代码:
#include <iostream>
#include <vector>
using namespace std;

class A {
public:
    A() { cout << "A()" << endl; }
    ~A() { cout << "~A()" << endl; }
    A(const A&) { cout << "A(A&)" << endl; }
};

int main()
{
    A a[5];    // 内置数组和
    cout << "=== ^_^ ===" << endl;
    vector<A> v(5);    // 标准容器都不用显示调用析构函数。
    cout << "main returns" << endl;

    return 0;
}
结果是:
A()
A()
A()
A()
A()
=== ^_^ ===
A()    # 我的编译器是构造了一个临时对象
A(A&)    # 然后用拷贝构造函数初始化的 vector 里的 5 个对象。
A(A&)
A(A&)
A(A&)
A(A&)
~A()    # vector 里的对象一初始化完毕,立刻就析构了那个临时对象。
main returns
~A()    # main 之后,所有 10 个对象全被析构。
~A()
~A()
~A()
~A()
~A()
~A()
~A()
~A()
~A()
你写的那个程序,p 是你自己分配的。既不是数组,也不是标准容器。你那里其实有 20 个对象,vector 拷贝走的那 10 个你就不用费尽管了,你自己申请的这 10 个还是得你自己释放。
书上就是再提醒你,如果你不是用的数组或者标准容器,那么可能你就要自己注意调用相关对象的析构函数了。
2012-08-24 01:41
mfs111116
Rank: 2
来 自:山东烟台
等 级:论坛游民
帖 子:28
专家分:38
注 册:2012-8-22
收藏
得分:0 
深奥了点,没看懂,我会努力的……呵呵
2012-08-24 18:03
humy
Rank: 2
等 级:论坛游民
帖 子:69
专家分:18
注 册:2012-7-23
收藏
得分:0 
回复 3楼 pangding
1.A & 和A *都不是A,即p,qa都不是A类的对象,即使会运用析构函数也不会用A定义的析构函数啊?
2.这个例子是不是说p,qa,虽然超过作用于不能再被引用,但是他们的空间没被释放?还是说他们的空间也被释放了,只是用的不是析构函数。。。?还是qa这个指针所占内存被释放了,但他所指向的A类对象的内存没释放?
3.又想了一下,是不是p本身就没有占用内存?他只是a的别名。?所以没析构函数的事?
4.而对于指针,:“对象的引用或指针”和“删除指向动态内存分配对象的指针”中的指针一样吗?如果指针不一样,是取决于他指向的对象的内存的分配方式?比如A* m,n;
    A a;
    m=&a;
    n=new A();则m,n类型不一样,n就是所说的  指向动态内存分配对象的指针 (就是涉及new,delete的) ?
“当对象的引用或指针超出作用于时不会运行析构函数,只有删除指向动态内存分配对象的指针或实际对象而非对象的引用超出作用域时才会运行析构函数。 ”这句话前后的解释是m,n?   于是我把delete pa注释掉,在inner里加了delete qa;
输出
main begins
outer begins
A()
inner begins
A()
~A()
inner ends
~A()
outer ends
main returns
请按任意键继续. . .
所以我又想指针没有不同,要且仅有用了delete就会运行析构。。。
不知我的哪个想法是对的?
5.int *p=new int[10];用这个是了一下,成功了。int **p=new int[10];这个就出错了。。我又找了书,在操作符里,new和new【】是分别的两个操作符。。。那他这个p是不是不指数组,只是指int元素?。。。而int **p=new (int*)[10];或(int *)*p=new (int*)[10];也会有一大堆错。。。。
6.改了一下,把他们放在inner里看是不是只要数组,容器使命结束它就会自动运行析构。。好像是的,结果:
A()
A()
A()
A()
A()
=== ^_^ ===
A()
A(A&)
~A()
A()
A(A&)
~A()
A()
A(A&)
~A()
A()
A(A&)
~A()
A()
A(A&)
~A()
inner ends
~A()
~A()
~A()
~A()
~A()
~A()
~A()
~A()
~A()
~A()
main returns
请按任意键继续. . .
结合版主所说“你自己申请的这 10 个还是得你自己释放。”
我觉得我的这个观点对:   动态分配就是用new什么的,指向他的地址指针什么的不涉及A的析构,这个指针会自己释放的,析构是指释放这些new出来的空间。
对不?
2012-08-25 16:52
pangding
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:北京
等 级:贵宾
威 望:94
帖 子:6784
专家分:16751
注 册:2008-12-20
收藏
得分:0 
回复 5楼 humy

1.A & 和A *都不是A,即p,qa都不是A类的对象,即使会运用析构函数也不会用A定义的析构函数啊?
是的。
2.这个例子是不是说p,qa,虽然超过作用于不能再被引用,但是他们的空间没被释放?还是说他们的空间也被释放了,只是用的不是析构函数。。。?还是qa这个指针所占内存被释放了,但他所指向的A类对象的内存没释放?
是你说的最后那种情况。指针或者引用的内存都被释放了,但它们指向的对象的内存没有释放。
3.又想了一下,是不是p本身就没有占用内存?他只是a的别名。?所以没析构函数的事?
指针本身也是要占内存的,用 sizeof(p) 之类的语句给出的就是指针本身所要占的内存。但一般无论它指的是什么东西,指针本身占的内存都一样多。32 位的 cpu 一般是 4,64 的是 8 字节。
在观念或者思维上,把它们理解成 a 的别名也行,但 c++ 里没有别名这个概念。
指针是内置类型,和 int 之类的东西一样,一般不需要析构,但也不是不能析构。尤其在模类中,有时有显示调用模版参数的析构函数的必要。如果是析构的内置类型,编译可能只是简单地忽略这个语句。
4.而对于指针,:“对象的引用或指针”和“删除指向动态内存分配对象的指针”中的指针一样吗?如果指针不一样,是取决于他指向的对象的内存的分配方式?比如A* m,n;
    A a;
    m=&a;
    n=new A();则m,n类型不一样,n就是所说的  指向动态内存分配对象的指针 (就是涉及new,delete的) ?
“当对象的引用或指针超出作用于时不会运行析构函数,只有删除指向动态内存分配对象的指针或实际对象而非对象的引用超出作用域时才会运行析构函数。 ”这句话前后的解释是m,n?   于是我把delete pa注释掉,在inner里加了delete qa;
输出。。。所以我又想指针没有不同,要且仅有用了delete就会运行析构。。。不知我的哪个想法是对的?
指针都是一样的,只是指向对象的本质可能不一样。你的例子里,m 和 n 的类型就是一样的。只是 n 指向的是动态分配的对象。
对象的引用是指 A &m = a; 这样的 m 称为 a 的引用。和 A *m = &a,在概念上还是有点区别的。如果是引用的话,一般不用管主体如何,析构主体不是引用的工作。对于指向非动态分配的指针也一样。
而动态的就要自己手动处理。delete 就会运行析构。只要你指针指的地址是曾经 new 分配的就行了,至于是不是一定就是接管收 new 分配的那个指针就无所谓。所以析构 pa 和 qa 都是可以的。但逻辑上不能 delete 两遍,也不能 delete 不是 new 分配的东西。
你的理解基本都是对的。
5.int *p=new int[10];用这个是了一下,成功了。int **p=new int[10];这个就出错了。。我又找了书,在操作符里,new和new【】是分别的两个操作符。。。那他这个p是不是不指数组,只是指int元素?。。。而int **p=new (int*)[10];或(int *)*p=new (int*)[10];也会有一大堆错。。。。
哦,有点明白你的问题了。你是觉得:
int *p = new int(5);
int *q = new int[5];
这两个语句都对很奇怪是吧?其实效果和这个很像:
int a = 5;
int b[5];
int *p = &a;
int *q = &b;
这里 p 指向的就是一个单蹦的元素。后者是一个数组。
而这个例子里第一个就用的是 new 操作符,而第二个是 new[] 操作符。new 操作符可以同时赋个初值,而 new[] 不行。对比直接定义,int a = 5 和 int b[5] = {1, 2, 3, 4, 5 } 都可以赋初值是不太一样的。

这个语句:int **p=new (int*)[10]; 的问题主要是出在 new 运算符的申请对象类型的识别模式对括号比较敏感。
正确的写法是去掉括号,或者变换一下括号的范围: int **p=new int*[10]; 或 int **p=new (int*[10]);
我的这个帖子里:https://bbs.bccn.net/viewthread.php?tid=364885&page=1#pid2087894
提了 new 加括号的问题,当时我讲的是优先级的问题,但其实不是。只是我当时想的也不是很清楚,所以没敢太仔细地讲。至于你写的那个为什么不对,不深究就是了。它的编译逻辑,我也没有搞清楚。

6.改了一下,把他们放在inner里看是不是只要数组,容器使命结束它就会自动运行析构。。好像是的,结果:。。。
结合版主所说“你自己申请的这 10 个还是得你自己释放。”
我觉得我的这个观点对:   动态分配就是用new什么的,指向他的地址指针什么的不涉及A的析构,这个指针会自己释放的,析构是指释放这些new出来的空间。
对不?
关于指针析不析构的问题,你前面几个问题也有提,就不再重复了。
new 和 delete 的逻辑是这样的,new 会先申请出足够的空间,用来容纳所要求的对象。之后,它就会在这些申请来的空间上执行申请对象的构造函数,如果是数组的话就会执行数次构造出数个对象。构造好了之后,才把这个空间的地址传回去。
delete 的逻辑其实就是 new 的逆。它会先在这些空间上执行一遍或数遍析构函数,先把对象销毁,然后再把销毁后的空间释放回去。
而至于那外指针本身,你写 int *p = new int[5] 其实也能看出来,这个指针本身不是动态分配的,它只是用来接收 new 的返回值而已。等你 delete 掉 p 之后,new 所产生效果就全被抵销了。p 过了生命期,自己自生自灭就无所谓了。不然 p 没以,假如你又没用其它指针指向那个动态分配的空间,就无法用 delete 回收了。这一般称作内存泄露。


关于你最开始问的第一个问题,书里之所以提,是在很多编程语言里,程序员没有管理内存的义务。想要什么对象引用它指向它就是了(其实在这样的语言里,也没有指针的概念,从而也没有指向的说法)。对象和引用是一体的,如果有两个符号引用了同一个对象,那么其中一个引用消失并不会回收对象,只会使它的引用减一。而如果一个对象的引用计数为 0,对会被自动回收。所以你的书提这句话,可能只是想告诉已经习惯这种观念的程序员,小心指针或引用的转移。因为引用的消失,不会再自动触发对象的析构了。
2012-08-27 03:07
humy
Rank: 2
等 级:论坛游民
帖 子:69
专家分:18
注 册:2012-7-23
收藏
得分:0 
回复 6楼 pangding
4小时前?   版主睡的太晚了吧。。。不能太辛苦了,身体是革命的本钱哦!
2012-08-27 08:34
humy
Rank: 2
等 级:论坛游民
帖 子:69
专家分:18
注 册:2012-7-23
收藏
得分:0 
回复 6楼 pangding
程序代码:
#include<iostream>
using namespace std;
class A {
public:
    A() { cout << "A()" << endl; }
    ~A() { cout << "~A()" << endl; }
    
};


int main(){
     A a;
    A & p=a;
    A* m=&a;
    cout<<"sizeof(a)"<<sizeof(a)<<"sizeof(p)"<<sizeof(p)<<endl;
    //cout<<"delete m"<<endl;
//    delete m;
//    cout<<"delete p"<<endl;
//    delete p;

    cout<<"main ends"<<endl;
    return 0;
    
}


1.上面例子不管是delete a,p,m都会出错。。。“指针是内置类型,和 int 之类的东西一样,一般不需要析构,但也不是不能析构。”上面出现error的例子是吗?只是不成立的例子而已。。。总结:他们及内置类型没有其他方法,只能等运行到超出作用域,机器自动删除它对吧?

2.输出
A()
sizeof(a)1sizeof(p)1
main ends
~A()
请按任意键继续. . .
p,a的大小一样。。。那这怎么办的?p的空间里放的的什么?引用可不是复制a的内容到p啊?“又想了一下,是不是p本身就没有占用内存?他只是a的别名。?所以没析构函数的事?
指针本身也是要占内存的,”。。。p不是引用吗?怎么又是指针呢?
3.
图片附件: 游客没有浏览图片的权限,请 登录注册
图片附件: 游客没有浏览图片的权限,请 登录注册
图片附件: 游客没有浏览图片的权限,请 登录注册
图片附件: 游客没有浏览图片的权限,请 登录注册
错了哎?。。。。。
谢谢
2012-08-27 10:12
pangding
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:北京
等 级:贵宾
威 望:94
帖 子:6784
专家分:16751
注 册:2008-12-20
收藏
得分:0 
回复 8楼 humy
1.上面例子不管是delete a,p,m都会出错。。。“指针是内置类型,和 int 之类的东西一样,一般不需要析构,但也不是不能析构。”上面出现error的例子是吗?只是不成立的例子而已。。。总结:他们及内置类型没有其他方法,只能等运行到超出作用域,机器自动删除它对吧?
delete 只能用于释放 new 申请来的空间。你的 a p m 都不是 new 出来,因此也不能用 delete 删除。
释放动态内存和析构不是一个概念,虽然有时释放会引发析构。显示调用析构函数是指 A a; a.~A() 这样的东西。
2.输出
A()
sizeof(a)1sizeof(p)1
main ends
~A()
请按任意键继续. . .
p,a的大小一样。。。那这怎么办的?p的空间里放的的什么?引用可不是复制a的内容到p啊?“又想了一下,是不是p本身就没有占用内存?他只是a的别名。?所以没析构函数的事?
指针本身也是要占内存的,”。。。p不是引用吗?怎么又是指针呢?
p 和 a 的大小一样,本来就应该是这样的了。引用几乎就可以看成那个对象本身。在实现上,有可能会为引用分配空间,但一般就是一个指针的空间而已。引用和指针有时候很像,A &p = a, *q = &a; 之后 p = 5 的效果就相当于 *q = 5。它们有很多相似之处,但语法上也有很多不同点。这个在之后的学习中慢慢体会就行了。
说 p 是说错了。之前写的代码年代久远我已经快忘了。一般举例子都是用 p、ptr 做指针,用 r 或者 ref 做引用。当时想当然了。
3.错了哎?。。。。。
这个从这点截图看不太出来。要想分析为什么出错,你得把代码给全。
不过指针的本来就很复杂,而且 c++ 如果用的好,确实用指针的情况少了很多。如果一时搞不清楚往后学就行了,有的东西放一阵子就能想通了。
2012-08-27 13:43
humy
Rank: 2
等 级:论坛游民
帖 子:69
专家分:18
注 册:2012-7-23
收藏
得分:0 
回复 9楼 pangding
3.是:
int a = 5;
int b[5];
int *p = &a;
int *q = &b;

版主有举这个例子
试了,错了。。。
又改为int**q=&b;
int*[5]q=&b;
等一系列见截图,都是错的。。。
2012-08-27 22:51
快速回复:关于析构函数
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.096679 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved