4. numeric limits/輔助函數(shù)/comparison operator
一般而言辈灼,數(shù)值型別(numeric types)的極值是與平臺有關(guān)的。
C++標(biāo)準(zhǔn)程序庫通過template numberic_limits提供這些極值罪佳,
取代傳統(tǒng)C采用的預(yù)處理器常數(shù)(preprocessor constants)**,當(dāng)然二者都可使用。
整數(shù)常數(shù)定義在<climits>和<limits.h>。
浮點數(shù)定義于<cfloat>和<float.h>
新的極值概念有兩個優(yōu)點:提供了更好的型別安全型片效;可借此寫出一些template以核定(evaluate)這些極值。
note:C++ standard規(guī)定了各種型別必須保證的最小精度英古,如果能注意并運用這些價值就可寫出與平臺無關(guān)的程序。
4.1 class numeric_limits<>
使用template通常是為了對所有型別一次性的寫出一個通用解決方案昙读。但還可以在必要時以template為每個型別提供共同接口召调。
方法:不但提供通用性template,還提供其特化(specialization)版本,eg:numeric_limits
1. 通用性template,為所有型別提供缺省值:
namespace std
{
/* general numeric limits as default for any type
*/
template <class T>
class numeric_limits
{
public:
//no specialization for numeric limits exist
static const bool is_specialized = false;
//.. //other members that are meaningless for the general numeric limits
};
}
這個通用性template將成員is_specialized設(shè)為false唠叛,意思是對于型別T只嚣,無所謂極值的存在。
2. 各個具體型別的極值艺沼,由特化版本(specialization)提供:
namespace std
{
/* numeric limits for int
* - implementation defined
*/
template <> class numeric_limits<int>
{
public:
//yes, a specialization for numeric limits of int does exist
static const bool is_specialized = true;
static T min() throw()
{
return -2147483648;
}
static T max() throw()
{
return 2147483647;
}
static const int digits = 31;
//...
};
}
通用性numeric_limits template及其特化版本都放在<limits>頭文件中册舞。
C++ standard所囊括的特化版本涵蓋了所有數(shù)值基本型別:
bool/char/signed char/unsigned char/wchar_t、
short/unsigned short/int/unsigned int/long/ float/double/long double
class numeric_limits<>所有成員及其意義如下圖
4.2 float型別數(shù)值限定模板特殊化的示例(page62)
namespace std
{
template<> class numeric_limits<float>
{
public:
//yes,a specialization for numeric limits for limits of float does exist
static const bool is_specialized = true;
inline static float min() throw()
{
return 1.17549435E-38F;
}
inline static float max() throw()
{
return 3.40282347E+38F;
}
static const int digits = 24;
static const int digits10 = 6;
static const bool is_signed = true;
static const bool is_integer = false;
static const bool is_exact = false;
static const bool is_bounded = true;
static const bool is_modulo = false;
static const bool is_iec559 = true;
static const int radix = 2;
inline static float epsilon() throw()
{
return 1.19209290E-07F;
}
static const float_round_style round_style = round_to_nearest;
inline static float round_error() throw()
{
return 0.5F;
}
static const int min_exponent = -125;
static const int max_exponent = +128;
static const int min_exponent10 = -37;
static const int max_exponent10 = +38;
static const bool has_infinity = true;
inline static float infinity() throw() { return ...;}
static const bool has_quiet_NaN = true;
inline static float quiet_NaN() throw() { return ...;}
static const bool has_signaling_NaN = true;
inline static float signaling_NaN() throw() { return ...;}
static const bool has_denorm_loss = false;
inline static float infinity() throw() { return ...;}
static const bool traps = true;
static const bool tinyness_before = true;
};
}
note:數(shù)據(jù)成員是const或static障般,如此其值便在編譯期確定调鲸;
至于函數(shù)定義的成員,某些編譯器無法在編譯期間確定其值挽荡。
故同一份代碼在不同處理器上執(zhí)行可能得出不同浮點數(shù)藐石。
C++ standard保證,若denorm_absent為0則為false定拟,若denorm_present為1且denorm_indeterminate為-1則二者都為true于微。故可把has_denorm視為一個bool以判斷某型別是否允許"denormalized values"。
4.3 numeric_limits<> 使用范例(page64)
/* 此例用于展示 某些型別極值的可能運用(eg了解某型別的最大值或確定char是否有符號)
*/
#include <iostream>
#include <limits>
#include <string>
using namespace std;
int main()
{
// use textual representation for bool
cout << boolalpha;
// print maximum of integral type
cout << "max(short): " << numeric_limits<short>::max() << endl;
cout << "max(int): " << numeric_limits<int>::max() << endl;
cout << "max(long): " << numeric_limits<long>::max() << endl;
cout << endl;
// print maximum of floating-point types
cout << "max(float): " << numeric_limits<float>::max() << endl;
cout << "max(double): " << numeric_limits<double>::max() << endl;
cout << "max(long double): " << numeric_limits<long double>::max() <<endl;
// print whether char is signed
cout << "is_signed(char): " << numeric_limits<char>::is_signed << endl;
cout << endl;
// print whether numeric limits for type string exist
cout << "is_specialized(string): " <<
numeric_limits<string>::is_specialized << endl;
}
程序輸出結(jié)果與執(zhí)行平臺有關(guān)青自,如下是一種可能:
4.5 輔助函數(shù)/比較操作符(page66)
4.5.1 輔助函數(shù)
算法程序庫(定義于頭文件<algorithm>)內(nèi)含3個輔助函數(shù)株依,一個是兩值取大,一個是兩值取小延窜,第三個用于交換兩值恋腕。
1. 挑選較小值和較大值
namespace std
{
template <class T>
inline const T& min(const T& a, const T& b)
{
return b < a ? b : a;
}
template <class T>
inline const T& max(const T& a, const T& b)
{
return a < b ? b : a;
}
}
如果兩值相等,通常返回第一值(程序最好不要依賴這一點)需曾。
另一版本:接受額外的template參數(shù)作為“比較準(zhǔn)則”
namespace std
{
template <class T , class Compare>
inline const T& min (const T& a, const T& b,Compare comp)
{
return comp(b,a) ? b : a;
}
template <class T , class Compare>
inline const T& max (const T& a, const T& b,Compare comp)
{
return comp(a,b) ? b : a;
}
}
作為“比較準(zhǔn)則”的參數(shù)應(yīng)該是函數(shù)或仿函數(shù),接受兩參數(shù)并比較:
在某指定規(guī)則下吗坚,判斷第一個參數(shù)是否小于第二參數(shù)并返回判斷結(jié)果。
eg,code:
#include <algorithm>
using namespace std;
/*function that compares two pointers by comparing the values to which they point
*/
bool int_ptr_less (int* a, int* b)
{
return *a < *b;
}
int main()
{
int x = 17;
int y = 42;
int* px = &x;
int* py = &y;
int* pmax;
// call max() with sepcial comparison function
pmax = max (px, py, int_ptr_lesss);
//...
}
2. 兩值互換
函數(shù)swap()用于交換兩對象的值呆万。其泛型版定義于<algorithm>商源。
namespace std
{
template <class>
inline void swap(T& a, T& b)
{
T tmp(a);
a = b;
b = tmp;
}
}
當(dāng)且僅當(dāng)swap()所依賴的copy構(gòu)造函數(shù)和assignment操作行為存在時,這個調(diào)用才可能有效谋减。
swap()的最大優(yōu)勢:
透過template specialization或function overloading牡彻,可以為更復(fù)雜的型別提供特殊的版本:
可交換對象內(nèi)部成員而不是反復(fù)賦值,如此可節(jié)約時間出爹。
標(biāo)準(zhǔn)程序庫中所有容器都用了這項技術(shù)庄吼。eg:
一個容器僅含一個array和一個成員(用于指示元素數(shù)量),那么其特化版本的swap()可以是:
class MyContainer
{
private:
int* elems; // dynamic array of elements
int* numElems; // numbers of elements
public:
//...
// implementation of swap()
void swap(MyContainer& x)
{
std::swap(elems, x.elems);
std::swap(numElems, x.numElems);
}
//...
//overloaded global swap() for this type
inline void swap(MyContainer& c1, MyContainer& c2)
{
c1.swap(c2); // calls implementation of swap()
}
};
4.5.2 輔助操作符(Comparison Operators)(page69)
有四個template functions严就,分別定義了!= 总寻、>、<=梢为、>=比較操作符渐行,它們都是利用操作符== 和 <完成的轰坊。四個函數(shù)定義于<utility>。
namespace std
{
namespace rel_ops
{
template <class T>
inline bool operator!= (const T& x, const T& y)
{
return !(x == y);
}
template <class T>
inline bool operator> (const T& x, const T& y)
{
return y < x;
}
template <class T>
inline bool operator<= (const T& x, const T& y)
{
return !(y < x);
}
template <class T>
inline bool operator>= (const T& x, const T& y)
{
return !(x < y);
}
}
}
只要加上using namespace std::rel_pos上述四個比較操作符就自動獲得了定義祟印。
4.6 頭文件<cstddef>和<cstdlib> (page71)
4.6.1 <cstddef>各種含義
NULL通常表一個不指向任何對象的指針肴沫,即0(型別是int或long),但C中NULL常定義為(void*)0蕴忆。
C++ 中沒定義從 void*到任何其他型別的自動轉(zhuǎn)型操作颤芬。
NULL也定義于頭文件<cstdio>/<cstdlib>/<cstring>/<ctime>/<cwchar>/<clocale>。
4.6.2 <cstdlib>內(nèi)各種含義
常數(shù)EXIT_SUCCESS和EXIT_FAILURE用于作exit()的參數(shù)或main()的返回值套鹅。
經(jīng)由atexit()注冊的函數(shù)站蝠,在程序正常退出是會依注冊的相反次序被一一調(diào)用,
無論是通過exit()退出或main()尾部退出芋哭,都是如此沉衣,不傳遞任何參數(shù)。
exit()和abort()可在任意處終止程序運行减牺,無需返回main()豌习。
exit()會銷毀所有static對象,將所有緩沖區(qū)buffer清空拔疚,關(guān)閉所有I/O通道channels,
然后終止程序(之前會先調(diào)用由atexit()注冊的函數(shù))肥隆,
若atexit()注冊的函數(shù)拋出異常則會調(diào)用terminate()。
abort()會立刻終止函數(shù)且不做任何清理clean up工作稚失。
note:這兩個函數(shù)都不會銷毀局部對象local objects栋艳,
因為堆棧 輾轉(zhuǎn)開展動作stack inwinding 不會被執(zhí)行。
為確保所有局部對象的析構(gòu)函數(shù)被調(diào)用句各,應(yīng)用異常exceptions或正常返回機(jī)制吸占,再由main()離開。