面试问题 一编写程序判断一个变量是不是指针指针的判别拾遗C++ 中仍然支持 C 语言中的可变函数参数C++ 编译器的匹配调用优先级重载函数函数模板变参函数思路将变量分为两类: 指针 VS 非指针编写函数:指针变量调用时返回 true非指针变量调用时返回 false函数模板与变参函数的化学反应template< typename T >bool IsPtr(T* v) // match pointer{ return true;}bool IsPtr(…) // match non-pointer{ return false;}编程实验: 指针判断#include <iostream>using namespace std;class Test{public: Test() { }; virtual ~Test() { };};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 << “p is a pointer: " << IsPtr(p) << endl; cout << “i is a pointer: " << IsPtr(i) << endl; Test t; Test* pt = &t; cout << “pt is a pointer: " << IsPtr(pt) << endl; cout << “t is a pointer: " << IsPtr(t) << endl; // 注意这里!对象传入变参函数 return 0;}编译输出:test.cpp: In function ‘int main()’:test.cpp:40: warning: cannot pass objects of non-POD type ‘class Test’ through ‘…’; call will abort at runtime运行输出:p is a pointer: 1i is a pointer: 0pt is a pointer: 1非法指令存在的缺陷:变参函数无法解析对象参数,可能造成程序崩溃!!进一步的挑战:如何让编译器精准匹配函数,但不进行实际的调用?编程实验: 指针判断改进#include <iostream>using namespace std;class Test{public: Test() { }; virtual ~Test() { };};template< typename T >char IsPtr(T* v) // match pointer{ return ’d’;}int IsPtr(…) // match non-pointer{ return 0;}#define ISPTR(p) (sizeof(IsPtr(p)) == sizeof(char)) // 注意这里!int main(){ int i = 0; int* p = &i; cout << “p is a pointer: " << ISPTR(p) << endl; cout << “i is a pointer: " << ISPTR(i) << endl; Test t; Test* pt = &t; cout << “pt is a pointer: " << ISPTR(pt) << endl; cout << “t is a pointer: " << ISPTR(t) << endl; return 0;}输出:【无警告,无错误】p is a pointer: 1i is a pointer: 0pt is a pointer: 1t is a pointer: 0分析: sizeof(IsPtr(t)) 发生了什么?sizeof 是编译器的内置指示符;在编译过程中所有的 sizeof 将被具体的数值所替换;程序的执行过程与 sizeof 没有任何关系;编译器根据匹配规则匹配到具体的函数 int IsPtr(…); sizeof(IsPtr(t)); 编译器将计算函数返回值类型所占用的大小;使用计算出的数值整体替换 sizeof(IsPtr(t)),因此不会发生实际的运行调用。不会出现变参函数解析对象参数而出现的程序运行时错误。面试问题 二如果构造函数中抛出异常会发生什么情况呢?构造中的异常构造函数中抛出异常构造过程立即停止当前对象无法生成析构函数不会被调用对象所占用的空间立即收回工程中的建议不要在构造函数中抛出异常当构造函数可能产生异常时,使用二阶构造模式编程实验: 构造中的异常#include <iostream>using namespace std;class Test{public: Test() { cout << “Test() begin …” << endl; throw 0; cout << “Test() end …” << endl; } virtual ~Test() { cout << “~Test()” << endl; }};int main(){ Test* p = reinterpret_cast<Test*>(1); cout << “p = " << p << endl; try { p = new Test(); } catch(…) { cout << “Exception…” << endl; } cout << “p = " << p << endl; return 0;}输出:p = 0x1Test() begin …Exception…p = 0x1注意:“Test() end …” 没有打印 ==> 证明构造过程停止;"~Test()” 没有打印 ==> 证明析构函数不会被调用;p 的值没有发生改变 ==> 证明对象没有生成;内存分析:g++ -g test.cppvalgrind –tool=memcheck –leak-check=full ./a.out输出:对象所占用的内存空间被收回==28776== HEAP SUMMARY:==28776== in use at exit: 0 bytes in 0 blocks==28776== total heap usage: 2 allocs, 2 frees, 104 bytes allocated==28776== ==28776== All heap blocks were freed – no leaks are possible析构中的异常避免在析构函数中抛出异常!!析构函数的异常将导致: 对象所使用的资源可能无法完全释放编程实验: 析构中的异常#include <iostream>using namespace std;class Test{private: int* m_pointer;public: Test() { cout << “Test()” << endl; m_pointer = new int(0); } virtual ~Test() { cout << “~Test() begin …” << endl; throw 0; delete m_pointer; cout << “~Test() end …” << endl; }};int main(){ try { Test(); } catch(…) { cout << “Exception…” << endl; } return 0;}输出:Test()~Test() begin …Exception…小结C++ 中依然支持变参函数变参函数无法很好的处理对象参数利用函数模板和变参函数能够判断指针变量构造函数和析构函数中不要抛出异常以上内容参考狄泰软件学院系列课程,请大家保护原创!