C++ STL — 第4章 Utilities

Pairs:  #include <utility>

std::pair是一个未封装类:struct class

两个成员:first   second

一个函数:make_pair(const T1&, const T2&)

默认的构造函数对于基础类型会初始化:

std::pair<int, float> p;   //p.first =0   and p.second = 0

两个拷贝构造函数:默认的和模板

void f(std::pair<int, const char*>);
voif g(std::pair<const int, std::string>);
 
voif foo() {
    std::pair<int, const char*> p(42, "hello");
    f(p);  //内置的拷贝构造函数
    g(p);  //模板拷贝构造
}

Pair的比较:

namespace std {
    template<class T1, class T2>
    bool operator==(const std::pair<T1, T2>& x, const std::pair<T1, T2>& y)
    {
        return x.first == y.first && x.second == y.second;
    }
}
 
namespace std {
    template<class T1, class T2>
    bool operator<(const std::pair<T1, T2>& x, const std::pair<T1, T2>& y)
    {
        return x.first < y.first || (!(x.fist < y.fist) && x.second < y.second);
    }
}

make_pair  函数:

namespace std {
    template<class T1, class T2>
    pair<T1,T2> make_pair(const T1& x, const T2& y)
    {
        return pair<T1,T2>(x,y);
    }
}

void f(std::pair<int, const char*>);
voif g(std::pair<const int, std::string>);
 
voif foo() {
    f(std::make_pair(43, "hel"));  //内置的拷贝构造函数
    g(std::make_pair(43, "hel"));  //模板拷贝构造
}

在map和multimap容器里大量使用 pair表示键值对:


Class auto_ptr:智能指针以避免资源泄露

传统手动销毁资源new和delete,很容易忘记delete导致内存泄露:

void f()
{
    ClassA* aPtr = new ClassA;  //创建一个堆对象
    ...
    delete aPtr;  //销毁这个对象
}
改进版:

void f()
{
    ClassA* aPtr = new ClassA;  //创建一个堆对象
    try {
        ...
    } catch (...) {
        delete aPtr;
        throw;
    }
    ...
    delete aPtr;  //销毁这个对象
}
更好的选择:只能指针auto_ptr

#include <memory>
 
void f()
{
    std::auto_ptr<ClassA> pClassA(new ClassA);
    //...
 
    std::auto_ptr<ClassA> pClassAError = new ClassA; //error
}

auto_ptr类似于指针变量:提供了*解引用和->箭头取成员函数或对象操作。

但是,auto_ptr提供严格的所有者权限审察,一个auto_ptr对象管理它指向的资源,而这个资源不应该被其他对象拥有,不幸的是C++语言没有在语言级别上限制,需要程序员自己控制。导致这个情况的是拷贝构造函数和赋值操作符的处理。

std::auto_ptr<ClassA> ptr1(new ClassA);
std::auto_ptr<ClassA> ptr2(ptr1);
//now ptr2 has the ownership, when ptr2 delete and the object destroyed

std::auto_ptr<ClassA> ptr1(new ClassA);
std::auto_ptr<ClassA> ptr2;
ptr2 = ptr1;  //copy assignment
//效果同上

函数可以利用auto_ptr来传递所有权:

void sink(auto_ptr<ClassA>);  //sink get the ownership
 
//函数返回值拥有所有权
auto_ptr<ClassA> f()
{
    auto_ptr<ClassA> ptr(new ClassA);
    return ptr; //将所有权移交给函数调用者
}

当你不打算转移auto_ptr所有权的时候千万不要用它作为函数参数或者返回值,因为这很危险:

template <class T>
void bad_print(auto_ptr<T> p)
{
    if(p.get() == NULL)
    {
        cout << "NULL" << endl;
    } else
    {
        cout << *p << endl;
    }
}
 
客户端这样使用:
auto_ptr<int> p(new int);
*p = 10;
bad_print(p);  //delete the memory that p refer
*p = 20;  //runtime error

避免传递auto_ptr的引用到函数:

const 意味着你不能改变auto_ptr的所有权而非指针所指向的对象的值:

auto_ptr<int> void f()
{
    const auto_ptr<int> p(new int); //no ownership transfer
    auto_ptr<int> q(new int); //ownership transfer possible
 
    *p = 42; //ok
    bad_print(p);  //complie-time error
    *p = *q; //ok
    p = q; //error
    return p;  //error
}

当指针变量作为class的成员变量:不安全做法,可能导致资源泄露

class B {
private:
    A *pA1;
    A *pA2;
public:
    //当第二个new抛异常时候可能会导致资源泄露
    B(A a1, A a2)
        : pA1(new A(a1)), pA2(new A(a2))
    { }
    //同上
    B(const B& x)
        : pA1(new A(*x.pA1)), pA2(new A(*x.pA2))
    //拷贝运算符
    const B& operator=(const B& x)
    {
        *pA1 = *x.pA1;
        *pA2 = *x.pA2;
        return *this;
    }
 
    //析构函数
    ~B()
    {
        delete pA1;
        delete pA2;
    }
};

为了避免上述资源泄露,使用auto_ptr改进:

class B {
private:
    const auto_ptr<A> pA1;
    const auto_ptr<A> pA2;
public:
    //当第二个new抛异常时候可能会导致资源泄露
    B(A a1, A a2)
        : pA1(new A(a1)), pA2(new A(a2))
    { }
    //同上
    B(const B& x)
        : pA1(new A(*x.pA1)), pA2(new A(*x.pA2))
    //拷贝运算符
    const B& operator=(const B& x)
    {
        *pA1 = *x.pA1;
        *pA2 = *x.pA2;
        return *this;
    }
 
    //这里就不需要析构函数
};

注意:auto_ptr使用指南

    不能共享所有权

    不能应用于array,auto_ptr call delete not delete[]

    不是通用的智能指针

    针对容器,无用武之地:因为coping不是常规的复制,而是transfer所有权


一个小例子:auto_ptr转移所有权,注意const auto_ptr<T>& p const保证了函数不会转移所有权

#include <iostream>
#include <memory>   //auto_ptr头文件
 
using namespace std;
 
//为auto_ptr定义输出操作符<<
template <class T>
ostream& operator<<(ostream& os, const auto_ptr<T>& p)
{
    if(p.get() == NULL)
    {
        os << "NULL";
    } else
    {
        os << *p;
    }
    return os;
}
 
int main()
{
    auto_ptr<int> p(new int(42));
    auto_ptr<int> q;
 
    cout << "after initialization : " << endl;
    cout << "p = " << p << endl;  //p = 42
    cout << "q = " << q << endl;  //q = NULL
 
    q = p;
 
    cout << "after assigning auto_ptr : " << endl;
    cout << "p = " << p << endl;  //p = NULL
    cout << "q = " << q << endl;  //q = 42
 
    *q = *q + 58;
    p = q;
 
    cout << "after change *q and reassign : " << endl;
    cout << "p = " << p << endl;  //p = 100
    cout << "q = " << q << endl;  //q = NULL
    return 0;
}

auto_ptr<int> p = new int(9);  //error, 因为auto_ptr对基础类型的构造函数是explicit不能进行隐式转换

下面的小例子展示了auto_ptr的const用法:

#include <iostream>
#include <memory>   //auto_ptr头文件
 
using namespace std;
 
//为auto_ptr定义输出操作符<<
template <class T>
ostream& operator<<(ostream& os, const auto_ptr<T>& p)
{
    if(p.get() == NULL)
    {
        os << "NULL";
    } else
    {
        os << *p;
    }
    return os;
}
 
int main()
{
    const auto_ptr<int> p(new int(42));
    const auto_ptr<int> q(new int(0));
    const auto_ptr<int> r;
 
    cout << "after initialization : " << endl;
    cout << "p = " << p << endl;  //p = 42
    cout << "q = " << q << endl;  //q = 0
    cout << "r = " << r << endl;  // r = NULL
 
    *q = *p;
  //*r = *p; //error at compile
    *p = -77;
 
    cout << "after assigning values auto_ptr point to: " << endl;
    cout << "p = " << p << endl;  //p = -77
    cout << "q = " << q << endl;  //q = 42
    cout << "r = " << r << endl;  // r = NULL
 
    //q = p; //compile error
    //r = p; //compile error
    return 0;
}

Numeric limits:

C++ 标准库提供了numeric_limits模板:提供更安全的类型

平台无关的代码:尽量使用类型保证的最小精度

类型  最小大小
char1 byte = 8 bits
short int2 bytes
int2 bytes
long int4 bytes
float4 bytes
double8 bytes
long double8 bytes

class numeric_limits<>:   #include <limits>

#include <iostream>
#include <limits>
#include <string>
 
using namespace std;
 
int main()
{
    //对于bool类型,使用文本方式输出
    cout << boolalpha;
 
    cout << "max(short) : " << numeric_limits<short>::max() << endl;  //max(short) : 32767
    cout << "max(int) : " << numeric_limits<int>::max() << endl;  //max(int) : 2147483647
    cout << "max(long) : " << numeric_limits<long>::max() << endl;  //max(long) : 9223372036854775807
 
    cout << "max(float) : " << numeric_limits<float>::max() << endl;  //max(float) : 3.40282e+38
    cout << "max(double) : " << numeric_limits<double>::max() << endl;  //max(double) : 1.79769e+308
    cout << "max(long double) : " << numeric_limits<long double>::max() << endl;  //max(long double) : 1.18973e+4932
 
    cout << "is_signed(char) : " << numeric_limits<char>::is_signed << endl; //is_signed(char) : true
    cout << "is_specialized(string) : " << numeric_limits<string>::is_specialized << endl;  //is_specialized(string) : false
    return 0;
}

辅助的函数:Compare 也许是一个函数,也可能是一个函数对象

namespace std {
    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;
    }
}
//如果a == b 总是返回第二个
//于是两个参数的比较出来了
namespace std {
    template <class T, class Compare>
    inline const T& min(const T& a, const T& b, Compare comp)
    {
        return comp(b,a) ? a : b;
    }
 
    template <class T>
    inline const T& max(const T& a, const T& b)
    {
        return comp(a,b) ? b : a;
    }
}

max  min等函数包含在头文件<algorithm>

#include <iostream>
#include <algorithm>  //算法
 
using namespace std;
 
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 = max(px, py, int_ptr_less);
    cout << *pMax << endl;  //42
 
    int i = 0;
    long l = 1;
    //long m = max(i, l);  //error argument doesn't match
    long m = max<long>(i, l); //ok
    return 0;
}

swap in <algorithm>:

namespace std {
    template <class T>
    inline void swap(T& a, T& b)
    {
        T tmp(a);
        a = b;
        b = tmp;
    }
}

#include <iostream>
#include <algorithm>  //算法
 
using namespace std;
 
int main()
{
    int x = 17;
    int y = 42;
    int *pX = &x;
    int *pY = &y;
 
    swap(x, y);
 
    cout << "x = " << x << endl;  //42
    cout << "y = " << y << endl;  //17
    cout << "*pX = " << *pX << endl;  //42
    cout << "*pY = " << *pY << endl << endl; //17
 
    swap(pX, pY);
    cout << "x = " << x << endl;  //42
    cout << "y = " << y << endl; //17
    cout << "*pX = " << *pX << endl;  //17
    cout << "*pY = " << *pY << endl; //42
    return 0;
}

定制自己的swap:

class MyContainer {
private:
    int *elems; //dynamic array of elements
    int numElems;
public:
    void swap(MyContainer& x)
    {
        std::swap(elems, x.elems);
        std::swap(numElems, x.numElems);
    }
};
 
inline void swap(MyContainer& c1, MyContainer& c2)
{
    c1.swap(c2); //调用自己的swap()实现
}

定义在<cstddef>:

NULL:指针值没有定义或者没有值

size_t  :number of elements unsigned   

ptrdiff_t  :signed type for difference of point

offsetof() : offset of a member in structure


定义在<cstdlib>:

exit(int status)  退出程序

EXIT_SUCCESS

EXIT_FAILURE

abort()

atexit()   //call function on exit


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值