1、指针的判别
1.1、
拾遗
1.1.1、
C++中仍然支持C语言中的可变参数函数
1.1.2、
C++编译器的
匹配调用优先级
:
重载函数>函数模板>变参函数
1.2、
思路
1.2.1、
将变量分为两类:
指针 VS 非指针
1.2.2、
编写函数:
指针变量调用时回true
非指针变量
调用时返回
false
1.3、
函数模板与变参函数的化学反应
template<typename T> //优先匹配函数模板
bool IsPtr(T* v) // match pointer
{
return true;
}
//变参函数 //再匹配变参函数
bool IsPtr(...) // match non-pointer
{
return false;
}
/*********************判断这个变量是否为指针!************************/
#include <iostream>
#include <string>
using namespace std;
class Test
{
public:
Test()
{
}
virtual ~Test() //虚函数,子类重写,生成虚函数表
{
}
};
//模板函数-优先匹配
template <typename T>
char IsPtr(T* v)
{
return 'd'; //返回值为:char型。
}
//变参函数-匹配的优先级比模板函数低,注意返回值与模板函数不同,这是因为当向变参函数中传入自定义类类型,才出现
int IsPtr(...)
{
return 0; //返回值为int型。
}
//定义这个宏的主要目的是,为了传自定义类型给可变参数时,可能出现的上述问题,可以利用sizeof来判断返回值的大小,如果为1表示char型,为匹配了模板函数。为4表示int型,匹配到了变参函数,从而区别变量到底是指针还是非指针类型,注意巧妙的利用了sizeof编译期就能确定的特性,从而避开运行期的错误。
#define ISPTR(p) ((sizeof(IsPtr(p))) == (sizeof(char)))//编译期就能确定特性!!!(这种操作真的骚)
/*
template <typename T>
bool IsPtr(T* v) //match pointer//函数模板匹配指针,
{
return true;
}
bool IsPtr(...) //match non-pointer//函数模板匹配非指针的。
{
return false;
}
*/
int main()
{
int i = 0;
int* p = &i;
cout << "i is a pointer " << ISPTR(i) << endl;
cout << "p is a pointer " << ISPTR(p) << endl;
//cout << "i is a pointer " << IsPtr(i) << endl;
//cout << "p is a pointer " << IsPtr(p) << endl;
Test t;
Test* pt = &t;
cout << "t is a pointer " << ISPTR(t) << endl; // 对象
cout << "pt is a pointer " << ISPTR(pt) << endl;
//cout << "pt is a pointer " << IsPtr(pt) << endl;
//cout << "t is a pointer " << IsPtr(t) << endl; //出错,可变参数检测不出来对象是什么类型。
//因为C语言(兼容C语言)中的变参无法检测类是什么样的类型::
//如果直接调用IsPtr来判断自定义类类型,会出现错误,
//
return 0;
}
判断变量是否为指针的方案二
/************ 直接利用函数模板的重载 ***************/
#include <iostream>
#include <string>
using namespace std;
class Test
{
public:
Test()
{
}
virtual ~Test()
{
}
};
//模板函数
template <typename T>
bool IsPtr(T* v)
{
return true;
}
template <typename T>
bool IsPtr(T v)
{
return false;
}
int main()
{
int i = 0;
int* p = &i;
cout << "p is a pointer:" << IsPtr(p) << endl; //true
cout << "i is a pointer:" << IsPtr(i) << endl; //false;
Test t;
Test* pt = &t;
cout << "pt is a pointer:" << IsPtr(pt) << endl; //true
cout << "t is a pointer:" << IsPtr(t) << endl; //false;
return 0;
}
1.4、存在的缺陷及完善
1.4.1、
变参函数
无法解析
自定义类类型的对象参数
,可能造成程序崩溃
1.4.2、
可以
在编译期
就精确匹配结果,而
不需等到实际调用IsPtr时才确定
。思路是通过sizeof,具体见例子中的注释。
2、 构造函数中的异常
2.1、
当构造函数中抛出异常时
:
2.1.1、
构造函数立即停止。
2.1.2、
当前对象无法生成(譬如在堆空间上并不会生成地址。)
2.1.3、
析构函数不会被调用
2.1.4、
对象所占用的空间立即收回
2.2、
工程项目中的建议
2.2.1、
不要在构造函数中抛出异常
(注:
也可以在构造函数中try-catch可能的异常,并在异常发生时做善后的处理(如资源释放),最后再将这个异常抛出,以通知外部的函数。但建议不要这样做,因为有更好的二阶构造模式,二阶模式在内部自己处理了异常,而抛异常的方法是把异常处理再次丢给了外部的函数
)
2.2.2、
当构造函数可能产生异常时,使用
二阶构造模式
/********** 构造中的异常 ***********/
#include <iostream>
#include <string>
using namespace std;
class Test
{
public:
Test()
{
cout << "Test()..." << endl;
throw 0;
}
~Test()
{
cout << "~Test()" << endl;
}
};
int main()
{
Test* p = reinterpret_cast<Test*>(1);
try
{
p = new Test();
}
catch(...)
{
cout << "Exception..." << endl;
}
cout << "p = " << p << endl;
return 0;
}
//linux下可以用如下命令检查是否内存泄漏
// g++ -g 67-3.cpp
// valgrind --tool=memcheck --leak-check=full ./a.out
3、. 析构函数中的异常
3.1、析构函数的抛出异常导致:对象所使用的资源无法完全释放
3.2、避免在析构函数中抛出异常
4、 小结
4.1、C++中依然支持变参函数
4.2、变参函数无法很好的处理对象参数
4.3、利用函数模板和变参函数能够判断指针变量
4.4、
构造函数和析构函数中不要抛出异常