new中抛出的异常问题。
抛出异常?
w k,这么酷的名词,我岂能落后于时代的潮流。
管它3721,我抛,我抛,我再抛!
好了,这下问题来了:
在new中抛出异常的话,赋值过程无法完成(return在throw前,就先返回了,throw在return前,return就执行不到)。在最近一层的try-catch测试块中,编译器会调用delete来释放内存。但问题是,没有赋值怎么能释放?于是乎,又一个异常抛出,够酷吧,这下彻底没救了。
是不是new中就不能抛出异常啊?
问题点数:200、回复次数:20Top
1 楼ripper(rIPPER)回复于 2001-08-29 16:30:11 得分 0
new里面还要甩异常啊~~ 倒~~ Top
2 楼fsb_12345(myself)回复于 2001-08-29 16:33:22 得分 0
gzTop
3 楼james_razor(蹬三轮的)回复于 2001-08-29 16:46:31 得分 0
比如说,内存不够的时候,我抛之。
但tmd的delete你瞎忙乎什么呢,该删的时候不删,不用你删你到挺起劲的。
new你也正是的,你抛就抛呗,没人不让你抛,但好歹你也给那个变量赋个NULL,delete就不会不识好歹的大叫“有异常!”了。
new委屈的:这也不是我的错,系统这样规定的。
wk,那你找个人把系统干掉,再找个人把你也干掉,有这样的废物系统,还有你这样的废物指令,你们两个合起来整我啊。Top
4 楼xiterator(xi)回复于 2001-08-29 16:51:34 得分 0
全局void* operator new中throw std::bad_alloc()异常时,是由于所请求的内存没有申请到,所以对于heap没有什么要做的工作(包括delete的调用也不需要),可以说全局void* operator new中抛出异常客户代码/库代码没有什么除了撤消调用stack frame中的对象或信息外没有什么特别需要做的。Top
5 楼james_razor(蹬三轮的)回复于 2001-08-29 16:56:56 得分 0
喂,老兄,你这话我怎么看上去这么别扭啊,老实交待,是不是字典翻译的?
其实在new之前,先对变量赋NULL,可以解决这个问题,但是不够地道,而且容易忘。Top
6 楼xiterator(xi)回复于 2001-08-29 17:20:10 得分 0
有些编译器在new失败时并不抛出异常(vc++),而是返回0。
若抛出bad_alloc()异常,客户要么没有catch,要么设置了catch块,可以在catch块中对这种情况加以处理(p=0之类的)。
关于exception handling 中new 抛出异常处理可参见 <<Inside The C++ Object Model>> p301.Top
7 楼onetwothree(onetwothree)回复于 2001-08-29 17:20:33 得分 60
调用new确实可能(因为存储耗尽)抛出异常。但是,对于用new分配的存储,编译器不会自动调用delete去释放(必须你自己调用去释放)。所以,你的假设是不成立的。Top
8 楼james_razor(蹬三轮的)回复于 2001-08-29 17:32:44 得分 0
我这不是假设,而是昨天调出来的问题。Top
9 楼shgciom(一条小鱼)回复于 2001-08-29 17:56:22 得分 0
把源代码公布!看看不就解决许多纠纷了!?Top
10 楼james_razor(蹬三轮的)回复于 2001-08-29 18:08:41 得分 0
明儿吧,谢谢各位。Top
11 楼james_razor(蹬三轮的)回复于 2001-08-30 11:47:57 得分 0
各位对不起,我错了。
new中抛出的异常不会引起delete操作。问题中的delete其实是由一个正常的析构函数调用的。调试过程中没看清楚,在new中一抛出异常,在delete就出现错误提示。给人的直觉这两件事情是直接因果相关的。也没细细推敲。浪费大家时间,对不起again。
而另一个例子:
#include <iostream>
using namespace std;
class Test
{
static int i;
public:
Test()
{
cout << "Constructing Test obj." << endl;
if (i ++ == 3)
throw 3;
}
~Test()
{
cout << "Destructing Test obj." << endl;
}
void *operator new [] (size_t size) throw (int)
{
cout << "Allocating memory." << endl;
return ::new char[size];
}
void operator delete [] (void *p)
{
cout << "Release memory." << endl;
::delete []p;
}
};
int Test::i = 0;
void main()
{
try
{
Test *t = new Test[10];
}
catch (int)
{
cout << "I catch it!" << endl;
}
}
抛出异常是在::new分配内存之后,构造函数中。异常导致构造函数失败,而对上一层的new[]来说,内存已经分配后产生了异常,已分配的内存不能白白让其废弃,否则岂不是有悖异常处理的原则,于是异常处理系统调用delete做清除工作。这里的delete接收参数并不是从new[]赋值的那个变量得到的,而是由系统记录的,所以不存在我所说的问题。
好了,分析结束,不正指出,恳请各位不吝赐教。
new:嘿嘿,不是我的错吧,愈加之罪何患无词,象你这样的人我见得多了,什么大风浪我没经历过,最后的结果还不是一样,我看你还是好好你蹬三轮这份很有前途的职业去吧,不要在这里丢人现眼了。
蹬三轮的蹬着车儿远去…… 一缕萧瑟影,两行辛酸泪。Top
12 楼Great_Bug()回复于 2001-08-30 12:55:55 得分 0
我是来听课的,,,,,搭你的车行不行?????Top
13 楼ed9er(始祖鸟)回复于 2001-08-30 13:12:03 得分 20
ctor中抛异常,可以专门写出一本书
所以我从来不,以后也决不会在我写的ctor里抛异常Top
14 楼james_razor(蹬三轮的)回复于 2001-08-31 09:27:13 得分 0
Because a constructor has no return value, you’ve previously had two choices to report an error during construction:
1. Set a nonlocal flag and hope the user checks it.
2. Return an incompletely created object and hope the user checks it.
This is a serious problem because C programmers have come to rely on an implied guarantee that object creation is always successful, which is not unreasonable in C where types are so primitive. But continuing execution after construction fails in a C++ program is a guaranteed disaster, so constructors are one of the most important places to throw exceptions – now you have a safe, effective way to handle constructor errors. However, you must also pay attention to pointers inside objects and the way cleanup occurs when an exception is thrown inside a constructor.
(摘自Thinking in C++)Top
15 楼cgaga(红枫剪影)回复于 2001-08-31 11:37:14 得分 0
永远别在构造函数和析构函数中干那些请求系统资源的傻事
一切OK!Top
16 楼binglex()回复于 2001-08-31 11:48:56 得分 20
一般在构造函数中只是简单的赋值,不要请求内存分配什么的,因为构造函数没有返回值,你不知道是否成功;
好的做法是构造函数中把指针设NULL,然后专门加个Init()函数,进行内存分配等可能出错的初始化工作Top
17 楼xiterator(xi)回复于 2001-08-31 14:23:22 得分 100
VC++在设计类时,经常采用的就是二次对象构造法,用起来感觉别扭,明明一步的工作要二步来做,而出错时的处理基本上与在构造函数中throw异常处理相同,而且程序又有多少次会在构造函数中出错呢?看看C++ creator Bjarne Stroustrup关于这方面的意见:
Why doesn't C++ provide a "finally" construct?
Because C++ supports an alternative that is almost always better: The "resource acquisition is initialization" technique (TC++PL3 section 14.4). The basic idea is to represent a resource by a local object, so that the local object's destructor will release the resource. That way, the programmer cannot forget to release the resource. For example:
class File_handle {
FILE* p;
public:
File_handle(const char* n, const char* a)
{ p = fopen(n,a); if (p==0) throw Open_error(errno); }
File_handle(FILE* pp)
{ p = pp; if (p==0) throw Open_error(errno); }
~File_handle() { fclose(p); }
operator FILE*() { return p; }
// ...
};
void f(const char* fn)
{
File_handle f(fn,"rw"); // open fn for reading and writing
// use file through f
}
In a system, we need a "resource handle" class for each resource. However, we don't have to have an "finally" clause for each acquisition of a resource. In realistic systems, there are far more resource acquisitions than kinds of resources, so the "resource acquisition is initialization" technique leads to less code than use of a "finally" construct.
Also, have a look at the examples of resource management in Appendix E of The C++ Programming Language.
Top
18 楼james_razor(蹬三轮的)回复于 2001-08-31 16:12:15 得分 0
就是就是,C++提供了,为什么不用。xiterator之言深得吾心。
还有,回复的功能有个设计缺陷,明明排好的程序,发出去后tab就没了,全部在一排,nnd。zdg看到没有,看到了就麻烦你请改一改,谢谢。Top
19 楼cnss(飞碟)回复于 2001-08-31 16:26:42 得分 0
听课Top
20 楼binglex()回复于 2001-09-03 11:07:04 得分 0
这个帖子是不是有问题了,怎么散完分了,没有显示呢??Top




