STL通用工具

通用工具Utilities

C++程序库中的通用工具:它们一般由短小精悍的类和函数组成,执行一般性的工作:
1.通用类型  general types
2.一些重要的C函数
3.数值极值 numeric limits

大部分的通用工具定义在C++的utility头文件中,某些辅助函数定义在algorithm头文件中。


1.pairs  对组
class pair将两个值视为一个单元,在map和multimap中使用pair来管理键值对(key-value)。

struct pair定义在标准库的utility中:

namespace std{
 template <class T1,class T2>
 struct pair{
  typedef T1 first_type;
  typedef T2 second_type;

  T1 first;
  T2 second;

  pair():first(T1()),second(T2()){}         //默认的初始化
  pair(const T1& a, const T2& b):first(a),second(b){}
  template <class U,class V>
  pair(const pair<U,V>& p):first(p.first),second(p.second){} //模板构造函数,可能存在隐式类型转换

  template <class T1,class T2>
  bool operator== (const pair<T1,T2>&,const pair<T1,T2>&);
  template <class T1,class T2>
  bool operator< (const pair<T1,T2>&,const pair<T1,T2>&);//比较时第一值具有较高的优先级
  template <class T1,class T2>
  pair<T1,T2> make_pair(const T1& x,const T2& y){return pair(x,y);}
  //convinience function

pair被定义为struct,而不是class,那么所有成员都是public的,可以直接存取pair的个别值。

C++标准库中,凡是必须返回两个值的函数,都使用pair类。

2.class auto_ptr   
a kind of smart pointer,help programmer to void memory leak when exception happens.

使用auto_ptr的动机:
申请资源,如果发生异常,资源释放没有执行。那么需要捕捉所有的异常,并在catch子句中释放资源。
这样多个catch语句的中都要释放资源。

只能指针保证,只要自己被摧毁,一定连带释放所指向的资源。
auto_ptr是区域变量,无论正常退出,还是异常退出,只要是退出,它就一定会被摧毁。它是它所指对象的拥有者。

#include<memory>
void f(){
 std::auto_ptr<A> ptr(new A());
没有定义++操作,不能做++操作。
std::auto_ptr<A> ptr1(new A());  //ok
std::auto_ptr<A> ptr2 =  new A;   //error

auto_ptr拥有权的转移:
auto_ptr的copy构造函数和赋值操作符将对象拥有权交出去。
std::auto_ptr<A> ptr1(new A);
std::auto_ptr<A> ptr2(ptr1);   //ptr1对象拥有权交给了ptr2
                 or   ptr2 = ptr1;  //ptr1对象拥有权交给了ptr2,若ptr2原来拥有指向其他对象,这个对象会被delete掉。

只有auto_ptr可以拿来当做另一个auto_ptr的初值,普通的指针不可以,不能以普通指针的赋值方法初始化auto_ptr。

拥有权的转移,使得一个函数使用auto_ptr将拥有权转移给另一个函数。

auto_ptr语意就有转移所有权,那么如果不想转移所有权,就应该避免使用auto_ptr。当把auto_ptr作为参数传入其他函数时,那么就意味着拥有权的终结。如果不注意这个细节,可能带来未知的错误。
std::auto_ptr<A> p(new A());
*p = 41;
bad_print(p);  // auto_ptr会交出所有权,*p所指会被销毁
*p = 1;        // runtime error
同样使用Reference传递auto_ptr让人难以捉摸,也要避免使用这种糟糕的方法。
总之,auto_ptr减少了不经意间转移所有权所带来的危险。

使用关键字const,那么不能修改auto_ptr的所有权。
const std::auto_ptr<A> p(new A());
*p = 2;
bad_print();           //runtime error 不能转交拥有权
*p = 1;                //可以修改指针所指对象的值
p  = q;                //runtime error

auto_ptr作为成员之一,当对象删除时,auto_ptr会自动删除它所指的成员对象,于是也就不需要析构函数了。但是auto_ptr意味着要自己重写COPY构造函数和==操作符重载函数。
如果无意转交拥有权,那么使用const auto_ptr.

auto_ptr错误运用实例:
1.auto_ptr之间不能共享拥有权
2.不存在针对array的auto_ptr
3.auto_ptr并不是四海通用的smart指针,如适用的计数型指针
4.auto_ptr并不符合STL容器对元素的要求,因为在copy和赋值前后,原本的值和之后的值不相等。
切记,非const的auto_ptr并不比普通的指针更安全,不应该以任何方式传递auto_ptr。

namespace std{
 //auxiliary type  to enable copies and assignments
 template<class Y> struct auto_ptr_ref{
  Y* yp;
  auto_ptr_ref(Y* rhs):yp(rhs){}
 }
 
 template<class T> class auto_ptr{
  private:
  T * ap;

  public:
  typedef T element_type;
  
  //constructor
  explicit auto_ptr(T* ptr = 0)throw() :ap(ptr){}

  //copy constructors,capture ownership
  auto_ptr(auto_ptr& rhs)throw() :ap(release(rhs)){}          
     template<class U> auto_ptr(auto_ptr<U>& rhs) throw(): ap(release(rhs)){}  //implicit copy

  //assignment constructors
  auto_ptr& operate=(auto_ptr& rhs) throw(){reset(release(rhs)); return *this;};
  template<class U> auto_ptr& operater=(auto_ptr<U>&) throw(){reset(release(rhs));
   return *this;}                                           //implicit assignment

  //destructor
  ~auto_ptr()throw(){delete ap;}

  //value access
  T* get() const throw(){return ap;}            
  T& operater*() const throw(){return *ap;}            //deference operater
  T* operater->() const throw(){return ap;}           //member access operater

  //release ownership
  T* release() throw(){T* temp(ap); ap = 0; return temp;}

  //reset value
  T* reset(T* ptr = 0)throw(){if(ap != ptr){delete ap; ap =  ptr;}}

  //conversions :cann't copy const auto_ptr
  public:
  auto_ptr(auto_ptr_ref<T>) throw();
  auto_ptr& operater=(auto_ptr_ref<T> rhs) throw();
一般的拷贝函数肯定会拷贝参数的,如果参数被定义为Reference to const object,那么发生拷贝,ownership发生改变,这将违背const本意。我们在前面已经强调过,当使用拷贝时,将auto_ptr参数定义为const很容易让人混淆。因为对于auto_ptr,拷贝就意味着ownership的转移,而const试图去组织这种ownership的转移。

变通的办法是找到一种办法,让右值变左值。rvalue----》lvalue。
引入auto_ptr_ref,协助将右值转化为左值,而不是去尝试const auto_ptr&这样糟糕的办法。


3.数值极限Numeric limits
一般来讲,数值极限是与平台相关的。C++标准库使用template numeric_limits提供了这些极值,取代了传统C语言所采用的预处理常数preprocessor constants。
这些预处理常数定义依然可以使用,整数常数定义在climits和limits.h头文件中,而浮点型常数定义在cfloat和float.h头文件中。

提供通用的template,同时提供其特化specialization版本。
1.common:
namespace std{
 template <class T>
 class numeric_limits{
 public:
 static const bool is_specialized = false;
2.specialization  
namespace sta{
 template < > class numeric_limits<int>{
 public:
  static const bool is_specialized = true;
  static T min()throw(){return -2147483648;}
  static T max()throw(){return 2147483648;}
  static const int digits = 31;

使用范例:
numeric_limits<int>::max()                      // int类型最大取值
numeric_limits<float>::is_signed                 // 是否带符号

4.辅助函数
算法程序库中定义于头函数algorithm中:
1.求最大值和最小
namespace{
 template <class T>
 inline const T& min(const T& a,const T& b){return a<b?a:b;}
 template <class T>
 inline const T& max(const T& a,const T& b){return a<b?b:a;}
加入比较函数的版本:
namespace{
 template <class T,class Compare>
   inline const T& min(const T& a,const T& b,Compare comp){ return comp(a,b)?a:b;}
 template <class T,class Compare>
   inline const T& max(const T& a,const T& b,Compare comp){ return comp(a,b)?b:a;}
作为比较函数的comp应该是一个函数或者是一个仿函数functor。

2.两值交换swap
template <class T> void swap(T& a,T& b){
 T tmp(a); a = b; b = temp;
}

5.辅助操作符
定义在头文件utility中,!=,>,>=,<=,它们是由<和==来实现的,那么只要定义了<和==就可以实现了。
namespace rel_ops{
template <class T>
inline bool operater!=(const T& a,const T& b){return !(a == b);}
template <class T>
inline bool operater<=(const T& a,const T& b){return !(b < a);}
template <class T>
inline bool operater>(const T& a,const T& b){return (b < a);}
template <class T>
inline bool operater>=(const T& a,const T& b){return !(a < b);}

使用时,using namespace std::rel_ops;  ,就可以使用这些其他的比较符了。

6.头文件
cstddef :
C++中避免使用晦涩的NULL,C++中NULL为整型。
size_t:         无符号类型大小,常用来标识size长度
    ptrdiff_t:      有符号类型,用来标示指针距离
offsetof:      表示一个成员在struct和union中的偏移量

cstdlib:
exit(int status);              //退出前做大量的清理工作,销毁所有的static对象,清空缓冲区,关闭所有I/O                                      通道,终止程序(之前,调用经由atexit()登陆的函数),如果atexit发生                                       异常,调用terminate();
    EXIT_SUCCESS  
EXIT_FAILURE
abort();                              //退出不做任何的清理工作
atexit(void (*function))

exit和abort函数都不会消除局部对象,因为堆栈辗转Stack unwinding开展动作不会执行。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值