67_經典問題解析五

1. 面試題:編寫程序判斷一個變量是不是指針。

拾遺

  • C++中仍然支持C語言中的可變參數函數
  • C++編譯器的匹配調用優先級
    (1) 重載函數
    (2) 函數模板
    (3) 變參函數

思路:
將變量分為兩類:指針 vs 非指針
編寫函數:
指針變量調用時返回true
非指針變量調用時返回false
通過函數模板變參函數的結合:

編程說明:指針判斷解決方案初步嘗試

#include <iostream>
#include <string>

using namespace std;

class Test
{
public:
    Test()
    {
    }
    
    virtual ~Test()
    {
    }
};

template
<typename T>
bool IsPtr(T* t)
{
    return true;
}

bool IsPtr(...)
{
    return false;
}

int main()
{
    int i = 0;
    int* p = &i;
    
    cout << "p is a pointer : " << IsPtr(p) << endl;
    cout << "i is NOT a pointer : " << IsPtr(i) << endl;
    
    Test t;
    Test* pt = &t;
    
    cout << "pt is a pointer : " << IsPtr(pt) << endl;
//  cout << "t is NOT a pointer : " << IsPtr(t) << endl;        // error
    
    return 0;
}

輸出結果:

p is a pointer : 1
i is NOT a pointer : 0
pt is a pointer : 1

存在問題:IsPtr(t)報錯:cannot pass objects of non-trivially-copyable type ‘class Test’ through ‘...’
問題分析:變參函數源自于C語言,是否支持對象的解析。
進一步優化:如何讓編譯器精確匹配函數,但不進行實際的調用?

編程說明:指針判斷解決方案完成版

#include <iostream>
#include <string>

using namespace std;

class Test
{
public:
    Test()
    {
    }
    
    virtual ~Test()
    {
    }
};

template
<typename T>
char IsPtr(T* t)
{
    return 'd';
}

int IsPtr(...)
{
    return 0;
}

// sizeof是編譯器內置指示符,因此,下面的 == 在編譯期就會完成
#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 NOT a pointer : " << ISPTR(i) << endl;
    
    Test t;
    Test* pt = &t;
    
    cout << "pt is a pointer : " << ISPTR(pt) << endl;
    cout << "t is NOT a pointer : " << ISPTR(t) << endl;        // error
    
    return 0;
}

輸出結果:

p is a pointer : 1
i is NOT a pointer : 0
pt is a pointer : 1
t is NOT a pointer : 0

2. 面試題:如果構造函數中拋出異常會發生什么情況?

構造函數中拋出異常:
(1) 構造過程立即停止
(2) 當前對象無法生成
(3) 析構函數不會被調用
(4) 對象所占的空間立即收回

工程項目中的建議:
(1) 不要在構造函數中拋出異常
(2) 當構造函數可能產生異常時,使用二階構造模式

編程說明:構造中的異常

#include <iostream>
#include <string>

using namespace std;

class Test
{
public:
    Test()
    {
        cout << "Test()" << endl;
        throw 0;
    }
    
    virtual ~Test()
    {
        cout << "virtual ~Test()" << endl;
    }
};

int main()
{
    Test* p = reinterpret_cast<Test*>(1);
    
    cout << "p = " << p << endl;
    
    try
    {
        p = new Test();
    }
    catch(...)
    {
        cout << "Exception ..." << endl;
    }
    
    return 0;
}

輸出結果:

p = 0x1
Test()
Exception ...

3. 面試題:析構函數中拋出異常會發生什么情況?

析構函數的異常將導致:對象所使用的資源無法完全釋放。
因此:避免在析構函數中拋出異常

4. 小結

  • C++中依然支持變參函數
  • 變參函數無法很好的處理對象參數
  • 利用函數模板變參函數能能夠判斷指針變量
  • 構造函數和析構函數中不要拋出異常
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容