2014-05-23 112 views
5

不幸的是,我調用第三方庫時必須執行縮小轉換。我不想在我的發佈版本中施加開銷,所以會使用static_cast。但是,它是一個數組索引,如果它最終呈負值,可能會導致一些娛樂。有沒有什麼方法可以在調試模式下創建一個安全的強制轉換,只有這樣才能檢查這個值以確保在轉換過程中沒有任何損失?我能想到的唯一方法是使用宏,而我寧願不使用宏。C++ static_cast與斷言

例如,在發佈和調試模式下使用MSVC:

int main() { 
    long long ll = std::numeric_limits<long>::max(); 
    ++ll; 
    std::cout << ll << "\n"; 
    long l = static_cast<long>(ll); 
    std::cout << l << "\n"; 
} 

結果的輸出:在同一

template<class to, class from> 
to checked_static_cast(const from& from_value) { 
    to to_value = static_cast<to>(from_value); 
    if (static_cast<from>(to_value) != from_value) 
    throw std::runtime_error("Naughty cast"); 
    return to_value; 
} 

#ifdef _DEBUG 
#define debug_checked_static_cast(to, val) checked_static_cast<to>(val) 
#else 
#define debug_checked_static_cast(to, val) static_cast<to>(val) 
#endif 

int main() { 
    try { 
    long long ll = std::numeric_limits<long>::max(); 
    ++ll; 
    std::cout << ll << "\n"; 
    long l = debug_checked_static_cast(long, ll); 
    std::cout << l << "\n"; 
    } catch (const std::exception& e) { 
    std::cerr << "ERROR: " << e.what() << "\n"; 
    } 
} 

結果:

2147483648 
-2147483648 

使用宏在釋放模式下輸出,但在調試中的以下內容:

2147483648 
ERROR: Naughty cast 

有沒有更好的選擇?

注意:我忽略了我們可能從一個足以導致此問題的陣列中享受的娛樂,也許這只是過分偏執,但我想這個概念可能具有除我的特定要求之外的其他應用。

+1

鑑於你正在嘗試做什麼,我沒有看到任何問題,完全按照你的方式來做(而且我通常是反宏觀的)。但考慮你是否真的希望在發佈模式下關閉此檢查,因爲你顯然認爲失敗的後果足以證明在調試模式下引發異常。 – dlf

回答

7

沒有宏觀需要,您可以簡單地使用函數體內的預處理條件:

template<class to, class from> 
inline to debug_checked_static_cast(const from& from_value) { 
    to to_value{static_cast<to>(from_value)}; 
#if _DEBUG 
    from round_trip{to_value}; 
    if (round_trip != from_value) 
    throw std::runtime_error("Naughty cast"); 
#endif 
    return to_value; 
} 

template<class to, class from> 
inline to debug_checked_coercion(const from& from_value) { 
    to to_value{from_value}; 
#if _DEBUG 
    from round_trip{to_value}; 
    if (round_trip != from_value) 
    throw std::runtime_error("Naughty cast"); 
#endif 
    return to_value; 
} 

然後使用

long l = debug_checked_coercion<long>(ll); 

請注意,我已經最小化使用static_cast,因爲縮小數字轉換不是必需的。

+0

第一個似乎很好,我喜歡它,但'debug_checked_coercion'給了我一個警告'C4244:'初始化':從'const __int64'轉換爲'long',可能丟失數據。這可能是因爲我在MSVC2010? – Rai

+0

@Rai:只需在這一個函數週圍使用編譯指示警告即可在本地禁用該警告。該功能的全部目的是執行縮小轉換。 (警告會給程序員的注意力帶來潛在的問題,我們的全部注意力都集中在這裏縮小的轉換) –

0

我傾向於同意dlf,如果它的重要性足以在Debug中引發異常,那麼您應該也可以在Release中這樣做。

如果我選擇了有時會崩潰的高效代碼,並且效率稍低的代碼,我不知道我會選擇什麼。

Paul。

+0

但是拋出異常不太可能防止崩潰。你是否建議在任何地方使用更廣泛的類型,而不是進行縮小轉換? –