标签:异常处理 句柄 thinkinginc++
如果一个对象的构造函数在执行过程中抛出异常,那么这个对象的析构函数就不会被调用。
Rawp.cpp
/**
* 书本:【ThinkingInC++】
* 功能:资源管理
* 时间:2014年10月8日20:19:03
* 作者:cutter_point
*/
#include <iostream>
#include <cstddef>
using namespace std;
class Cat
{
public:
Cat() { cout<<"Cat()"<<endl; }
~Cat() { cout<<"~Cat()"<<endl; }
};
class Dog
{
public:
void* operator new(size_t sz)
{
cout<<"分配一个Dog的空间"<<endl;
throw 47; //抛出异常,后面为了检验构造函数抛出异常的后果
}
void operator delete(void* p)
{
cout<<"回收一个Dog的空间"<<endl;
::operator delete(p);
}
};
class UseResources
{
Cat* bp;
Dog* op; //这个事类的组合
public:
UseResources(int count=1)
{
cout<<"UseResource的构造函数"<<endl;
bp=new Cat[count];
op=new Dog;
}
~UseResources()
{
cout<<"~UseResources的析构函数"<<endl;
delete [] bp; //回收数组空间
delete op;
}
};
int main()
{
try
{
UseResources ur(3);
}
catch(int)
{
cout<<"inside handler"<<endl;
}
return 0;
}
·在构造函数中捕获
·在对象的构造函数中分配资源,并且在对象的析构函数中释放资源。
Wrapped.cpp
/**
* 书本:【ThinkingInC++】
* 功能:使所有事物都成为对象,防止资源泄露
* 时间:2014年10月8日20:19:38
* 作者:cutter_point
*/
#include <iostream>
#include <cstddef>
using namespace std;
template<class T, int sz=1>
class PWrap
{
T* ptr; //一个这个类型的指针
public:
class RangeError {}; //这是一个异常类
PWrap()
{
ptr=new T[sz]; //构造函数,给数据成员创建初值
cout<<"PWrap的构造函数"<<endl;
}
~PWrap()
{
delete [] ptr; //析构
cout<<"PWrap的析构函数"<<endl;
}
T& operator [] (int i) throw(RangeError) //抛出一个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<<"分配狗的空间"<<endl;
throw 47; //内存不够抛出异常
}
void operator delete[](void* p)
{
cout<<"回收狗的内存空间"<<endl;
::operator delete[](p);
}
};
class UseResources
{
PWrap<Cat, 3> cats; //创建3只猫
PWrap<Dog> dog;
public:
UseResources() { cout<<"UseResources构造函数"<<endl; }
~UseResources() { cout<<"~UseResources析构函数"<<endl; }
void f() { cats[1].g(); }
};
int main()
{
try
{
UseResources ur;
}
catch(int)
{
cout<<"抛出异常,捕获一个整形的数值"<<endl;
}
catch(...)
{
cout<<"其他的捕获(...)"<<endl;
}
return 0;
}
RAII:资源获得式初始化
Unexcepted.cpp
/**
* 书本:【ThinkingInC++】
* 功能:关于设置自己的异常函数,来显示不可预知的异常
* 时间:2014年10月8日20:20:06
* 作者:cutter_point
*/
#include <exception>
#include <iostream>
#include <cstdlib>
using namespace std;
class Up {};
class Fit {};
void g();
void f(int i) throw(Up, Fit) //根据给的int值来抛出异常
{
switch(i)
{
case 1: throw Up();
case 2: throw Fit();
}
g(); //本来在版本一的g()只是被声明的时候是不会抛出任何异常的,但是后面又抛出了一个int型的异常
}
//定义函数g() 所以这里违反了异常抛出的规格(只有两种)
void g() { throw 47; }
void my_unexcepted() //这个用来设置在规格之外的异常抛出
{
cout<<"规格之外的异常抛出,不是Up也不是Fit"<<endl;
exit(0);
}
int main()
{
set_unexpected(my_unexcepted); //设置规格之外的异常将会调用的函数,忽略返回值
for(int i=1 ; i <= 3 ; ++i)
try
{
f(i);
}
catch(Up)
{
cout<<"抛出Up类型的异常"<<endl;
}
catch(Fit)
{
cout<<"抛出Fit类型的异常"<<endl;
}
return 0;
}
1)确保程序不是给自己赋值。如果是的话,到步骤6
2)给指针数据成员分配所需的新内存
3)从原来的内存区间向新分配的内存区拷贝数据
4)释放原有的内存
5)更新对象的状态,也就是把指向分配新堆内存地址的指针赋值给指针数据成员
6)返回*this
从上面的定义中的我们可以看到,句柄是一个标识符,是拿来标识对象或者项目的,它就象我们的姓名一样,每个人都会有一个,不同的人的姓名不一样,但是,也可能有一个名字和你一样的人。从数据类型上来看它只是一个16位的无符号整数。
管理其他资源的类
需要明确的第一点,strlen所作的仅仅是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符‘/0‘为止,然后返回计数器值。
SafeAssign.cpp
/**
* 书本:【ThinkingInC++】
* 功能:关于operator=的安全分配内存
* 时间:2014年10月8日20:20:41
* 作者:cutter_point
*/
#include <iostream>
#include <new> //为了抛出异常bad_alloc
#include <cstring>
#include <cstddef>
using namespace std;
class HasPointers
{
//这里设置一个句柄类来管理我们的数据
struct MyData
{
const char* theString;
const int* theInts;
size_t numInts;
//构造函数
MyData(const char* pString, const int* pInts, size_t nInts) : theString(pString), theInts(pInts), numInts(nInts) {}
}*theData; //这个指针是指向这个结构体的
//这里为了安全的分配内存,我们使用一个clone静态函数
static MyData* clone(const char* otherString, const int* otherInts, size_t nInts)
{
/*
需要明确的第一点,strlen所作的仅仅是一个计数器的工作,它从内存的某个位置(可以是字符串开头,
中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符'/0'为止,然后返回计数器值。
*/
char* newChars=new char[strlen(otherString)+1]; //吧这个字符串的长度加一,作为这个数组的长度,最后一位是'/0'
int* newInts;
//这里分配int类型的,避免异常
try
{
newInts=new int[nInts];
}
catch(bad_alloc&)
{
delete []newChars;
throw;
}
try
{
strcpy(newChars, otherString); //拷贝到newChars里面去
for(size_t i=0 ; i < nInts ; ++i)
newInts[i]=otherInts[i]; //吧otherInts里面的数据赋值给newInts
}
catch(...)
{
delete []newInts;
delete []newChars;
throw;
}
return new MyData(newChars, newInts, nInts);
}
//一个重载的clone,拷贝构造函数
static MyData* clone(const MyData* otherData)
{
return clone(otherData->theString, otherData->theInts, otherData->numInts);
}
//内存清理
static void cleanup(const MyData* theData)
{
//回收全部内存,只要使用了指针的,都要把指针指向的内存回收掉
delete theData->theString;
delete theData->theInts;
delete theData;
}
public:
//构造函数
HasPointers(const char* someString, const int* someInts, size_t numInts)
{
theData=clone(someString, someInts, numInts);
}
//拷贝构造函数
HasPointers(const HasPointers& source) { theData=clone(source.theData); }
//赋值拷贝运算符
HasPointers& operator=(const HasPointers& rhs)
{
//避免自赋值
if(this != &rhs)
{
MyData* newData=clone(rhs.theData->theString, rhs.theData->theInts, rhs.theData->numInts);
cleanup(theData);
theData=newData;
}
return *this;
}
//析构函数
~HasPointers() { cleanup(theData); }
//友元函数
friend ostream& operator<<(ostream& os, const HasPointers& obj)
{
os<<obj.theData->theString<<" : ";
for(size_t i=0 ; i < obj.theData->numInts ; ++i)
os<<obj.theData->theInts[i]<<' ';
return os;
}
};
int main()
{
int someNums[]={1, 2, 3, 4};
size_t someCount=sizeof(someNums)/sizeof(someNums[0]);
int someMoreNums[]={5, 6, 7};
size_t someMoreCount=sizeof(someMoreNums)/sizeof(someMoreNums[0]);
cout<<"这两个数组长度是:"<<someCount<<" : "<<someMoreCount<<endl;
HasPointers h1("Hello", someNums, someCount);
HasPointers h2("Goodbye", someMoreNums, someMoreCount);
cout<<h1<<endl;
h1=h2;
cout<<h1<<endl;
return 0;
}
标签:异常处理 句柄 thinkinginc++
原文地址:http://blog.csdn.net/cutter_point/article/details/39898239