【C++】 67_经典问题分析 五
生活随笔
收集整理的這篇文章主要介紹了
【C++】 67_经典问题分析 五
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
面試問題 一
編寫程序判斷一個變量是不是指針
指針的判別
-
拾遺
- C++ 中仍然支持 C 語言中的可變函數參數
-
C++ 編譯器的匹配調用優先級
- 重載函數
- 函數模板
- 變參函數
-
思路
- 將變量分為兩類: 指針 VS 非指針
-
編寫函數:
- 指針變量調用時返回 true
- 非指針變量調用時返回 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: 1 i is a pointer: 0 pt 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: 1 i is a pointer: 0 pt is a pointer: 1 t 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 = 0x1 Test() begin ... Exception... p = 0x1注意: "Test() end ..." 沒有打印 ==> 證明構造過程停止; "~Test()" 沒有打印 ==> 證明析構函數不會被調用; p 的值沒有發生改變 ==> 證明對象沒有生成;內存分析:
g++ -g test.cpp valgrind --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++ 中依然支持變參函數
- 變參函數無法很好的處理對象參數
- 利用函數模板和變參函數能夠判斷指針變量
- 構造函數和析構函數中不要拋出異常
以上內容參考狄泰軟件學院系列課程,請大家保護原創!
總結
以上是生活随笔為你收集整理的【C++】 67_经典问题分析 五的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2018年第41周-sparkSql搭建
- 下一篇: 菜鸟级springmvc+spring+