泛型编程的对象生存期问题

Alan S1 2008-09-24 08:46:01
#include "stdafx.h"
#include <iostream>
#include <cstddef>
#include <memory>
using namespace std;

template<class T, int sz = 1> class PWrap {
T* ptr;
public:
class RangeError {};//Exception class
PWrap() {
ptr = new T[sz];
cout << "PWrap constructor" << endl;
}
~PWrap() {
delete[] ptr;
cout << "PWrap destructor" << endl;
}
T& operator[](int i) throw(RangeError){
if(i >=0 && i < sz) return ptr[i];
throw RangeError();
}
};

class Cat {
public:
Cat() { cout << "Cat()" << endl; }
~Cat(){ cout << "~Cat()" << endl; }
void g() {}
};

class Dog {
public:
void *operator new[](size_t) {
cout << "Allocating a Dog" << endl;
throw 47;
}
void operator delete[](void* p) {
cout << "Deallocating a Dog" << endl;
operator delete[](p);
}
};

class UseResources {
PWrap<Cat, 3> cats;
PWrap<Dog> dog;
public:
UseResources() { cout << "UseResources()" << endl; }
~UseResources() { cout << "~UseResources()" << endl; }
void f() { cats[1].g(); }
};

int main(int argc, char* argv[])
{
try {
UseResources ur;
}
catch (int) {
cout << "inside handler" << endl;
}
catch(...) {
cout << "inside catch(...)" << endl;
}
return 0;
}


大家看看结果为什么~Cat()会被调用呢?
...全文
87 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
Alan S1 2008-09-24
  • 打赏
  • 举报
回复
但是Bruce Eckel说:在这里之所以能达到这样的效果,完全是模板的功劳,如果不用模板,似乎是没有办法了
Alan S1 2008-09-24
  • 打赏
  • 举报
回复
几句话加起来我就恍然大悟了:

1. “应该是Dog new时发生了异常,把控制权交给了catch中的处理语句.”
2. “而cat是完好保存在栈中的”
3. “发生异常的时候,cat已经构造完了.所以出了try块,cat可以析构”


非常感谢,觉得分不够的,我可以再加上去
帅得不敢出门 2008-09-24
  • 打赏
  • 举报
回复
dog资源的释放应该放在catch子句中处理
帅得不敢出门 2008-09-24
  • 打赏
  • 举报
回复
我12楼有误.
应该是Dog new时发生了异常,把控制权交给了catch中的处理语句.

有一个是这样说的:不要在构造与析构中抛出异常
独孤过儿 2008-09-24
  • 打赏
  • 举报
回复
有兴趣的搜一下这篇文章吧《C与C++中的异常处理》,我上班呢,没时间找...
帅得不敢出门 2008-09-24
  • 打赏
  • 举报
回复
Dog new时发生了异常,其构造函数是没法调用的. 
帅得不敢出门 2008-09-24
  • 打赏
  • 举报
回复
PWrap<Cat, 3> cats;
构造的时候:
PWrap() {
ptr = new T[3];//这里调用三次cat构造函数
cout << "PWrap constructor" << endl;
}
~PWrap() {
delete[] ptr;//出了try块cat生命周期结束,调用三次cat析构函数
cout << "PWrap destructor" << endl;
}

PWrap<Dog> dog;
构造的时候:
PWrap() {
ptr = new T[1];//调用的是void* DOG::operator new[](size_t)并有异常throw 47 处理异常
cout << "PWrap constructor" << endl;
}
发生异常的时候,cat已经构造完了.所以出了try块,cat可以析构,而dog没有办法
e_sharp 2008-09-24
  • 打赏
  • 举报
回复
UP
独孤过儿 2008-09-24
  • 打赏
  • 举报
回复
呵呵,你把cat的实例化和dog的实例化调换一下位置,看看结果是什么样了,就是改成下面的代码:

class UseResources {
PWrap<Dog> dog;
PWrap<Cat, 3> cats;
public:
UseResources() { cout << "UseResources()" << endl; }
~UseResources() { cout << "~UseResources()" << endl; }
void f() { cats[1].g(); }
};
Alan S1 2008-09-24
  • 打赏
  • 举报
回复
“当dog抛出了异常以后,由于cat是先压入栈中的,而dog是后压入栈中的,异

常处理程序按顺序出栈,则dog的析构函数没法执行(因为dog抛出了异常),而cat是完好保存在栈中的,所以cat的析构正常执行... ”


我推敲了一下字眼,发现后面的话就逻辑上还想不通啊
Alan S1 2008-09-24
  • 打赏
  • 举报
回复
“定义了UseResources ur;肯定会有销毁的时候”,,

错了,当发生异常的时候,再一定的情况下是不会调用析构函数的,我贴的程序主要意思是在抛出异常的情况下,在不使用auto_ptr的情况下,如何有效的将资源释放掉,这个程序是《thinking in c++》第二卷中的程序,而作者Bruce的写法就是采用模板,


我模板学地太差,无法理解cat的可以析构但是dog就无法析构
devil_zuiai 2008-09-24
  • 打赏
  • 举报
回复
我觉得不管怎么说
定义了UseResources ur;肯定会有销毁的时候,当ur销毁的时候会调用delete[] ptr;
调用delete[] ptr;的时候就会调用~Cat()了。
Alan S1 2008-09-24
  • 打赏
  • 举报
回复
fetag说地非常在理,你还是学生吗?就把C++学这么好了?
独孤过儿 2008-09-24
  • 打赏
  • 举报
回复
我的看法是,异常处理是和栈以及OS提供的功能密切相关的,在上面的代码中cat的析构函数正常调用了,而dog的析构函数没有调用,应该是由于

cat是先实例化的,而dog是后实例化的,并且异常是在dog中抛出的!当dog抛出了异常以后,由于cat是先压入栈中的,而dog是后压入栈中的,异

常处理程序按顺序出栈,则dog的析构函数没法执行(因为dog抛出了异常),而cat是完好保存在栈中的,所以cat的析构正常执行...

为了证明我说的,可以将cat和dog的实例化换一下位置,即先声明dog,后声明cat,这样应该cat的构造和析构都不会执行了...
独孤过儿 2008-09-24
  • 打赏
  • 举报
回复
我觉得 UseResources ur的生存期只在try{}块中,出了这个try{}块,生存期就结束了...析构函数自然也可以调用了...
xkyx_cn 2008-09-24
  • 打赏
  • 举报
回复
UseResources类里有用cat做为类型参数的模板类PWrap的实例

PWrap的构造和析构里会分别new,delete参数类ptr = new T[sz]; delete[] ptr;
这2个地方会调用模板参数类Cat的构造和析构函数
OenAuth.Core 2008-09-24
  • 打赏
  • 举报
回复
UseResources ur;
执行上面这句的时候肯定要执行PWrap<Cat, 3> cats;这句
这里面用到了Cat,这是通用函数的实例化(应该叫具体化吧??忘了什么化了),其实就和用类生成实例对象差不多一个意思,PWrap里面有 ptr = new T[sz];在实例化过程中这句话就是:ptr = new Cat[sz];这时Cat对像就生成了,主程序结束时,肯定要析构的

64,683

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧