《C++标准程序库》读书笔记(一)

1、非类型模板参数:类型(Type) 可以作为模板(template)参数,非类型(NonType)也可以作为模板(template)参数。因而非类型参数可被看做整个模板(template)类型的一部分。例如:bitset<N>
template <size_t N> class bitset;

当然,其中的N必须是一个编译器常量(即能够在编译器就确定变量的值)。

2、缺省模板参数(Default Template Parameters)

1)类模板可以有缺省的模板参数;

2)但函数模板不能有缺省的模板参数。

3、成员模板(Member Template )

     类的成员函数可以是一个模板函数。但这样的函数既不能是virtual也不能有缺省参数。

例如:

1) 类为实例类:

class MyClass

{

....

tempate<typename T> 

void fun(const T &); 

....
};

2)类为模板类:

template <typename T>

class MyClass

{

private:

T value;

public:

void assign(const MyClass<T> &other );  // other 必须和 *this 具有严格一样的类型


template <typename U>

void assign(const MyClass<U> &rhs);  // rhs 不一定和 *this 具有严格一样的类型,只要成员可被赋值(assignable)即可

};

3) Template Constructor

模板构造函数(template constructor)是模板成员函数的一种特殊形式。模板构造函数通常用于“在复制对象时实现(相似类型的)隐式转换”。注意,模板构造函数并不会隐藏(hide)隐式的拷贝构造函数(implicit copy constructor)。如果类型完全吻合,implicit copy constructor 就会被产生出来并被调用。

4、基本类型的显示初始化

void test_initial()
{
    int i1; // undefined value
    cout << "i1=" << i1;
    int i2 = int(); // i2 == 0
    cout << "i2=" << i2;
}
该特性的意义:

这个特性可以确保我们在撰写template程序代码时,任何类型都有一个确切的初始值。例如,下列函数中x被保证初始化为零。

template <class T>

void f()

{

T x = T();   // x 将被正确的初始化  

....
}

5、命名空间

    namespace,将不同的标志符号集合在一个具名作用域(named scope)内。

    using declaration, 通过using声明,我们可以避免一再写出冗长的namespace名称。例如以下声明:

    using josuttis::File; 

    会使File成为当前作用域内代表josuttis::File的一个同义字。

6、pair 的模板(拷贝)构造函数:

template<class U, class V> pair (const pair<U,V>& pr);

7、智能指针

#include <memory> // std::auto_ptr
#include <tr1/memory> // std::tr1::shared_ptr
#include <boost/scoped_ptr.hpp> // boost::scoped_ptr
8、数值极限(Numeric Limits)

头文件:

#include <limits>

类模板:

std::numeric_limits<T>
9、辅助函数

#include <algorithm>    // std::min std::max 

template <class T> const T& min (const T& a, const T& b);
template <class T> const T& max (const T& a, const T& b);

template <class T, class Compare>
  const T& min (const T& a, const T& b, Compare comp);
template <class T, class Compare>
  const T& max (const T& a, const T& b, Compare comp);

10、两值互换函数

#include <algorithm>    // std::swap
template <class T> void swap (T& a, T& b); // C++98
  
  
header
// moved from <algorithm> to <utility> in C++11
non-array (1)
template <class T> void swap (T& a, T& b)
  noexcept (is_nothrow_move_constructible<T>::value && is_nothrow_move_assignable<T>::value);
array (2)
template <class T, size_t N> void swap(T (&a)[N], T (&b)[N])
  noexcept (noexcept(swap(*a,*b)));

1)对于非基本类型的T来说,只有当T的copy构造和assignment操作行为存在时,swap才能达到预期的目的。

2)swap()的模板特化技术——能带来效率上的提升。针对特定的类撰写特定的swap()函数。

11、辅助型的比较操作符

在C++标准程序库的<utility>模块中,定义了  !=, >, <=, >= 四个模板函数,他们都是利用类型各自的 == 和 < 操作符来完成的。

值得注意的是,这四个比较操作符都位于std::rel_ops的次命名空间中。这里为什么要使用次命名空间?为了防止和用户定义的全局命名空间中的同类型操作符发生冲突。

#include <utility>  // 头文件
using namespace std::rel_ops;  //   !=, >, <=, >= 四个模板函数所在的次命名空间
12、头文件 <cstddef>

定义了常用的常量 NULL, size_t, ptrdiff_t, offsetof 等.

13、头文件 <cstdlib>

1) 定义了 EXIT_SUCCESS, EXIT_FAILURE用来当作exit(int status)的参数, 也可以当作main()的返回值。

2) abort.

3) atexit(void (* function) () ) : 经由 atexit() 登录的函数,在程序正常退出时会依照登录的相反次序被一一调用。

14、STL

     STL是C++标准程序库的核心,它深刻影响了标准程序库整体结构。STL包括容器containers、迭代器iterators、仿函数functors、算法algorithms等部分。STL赋予C++新的抽象层次。STL的基本观念是将数据和算法分离。数据由容器管理;而操作由可定制的算法定义之;迭代器则在二者之间充当粘合剂。STL这种将数据和操作(算法)分开对待,而不是合并考虑。因此从这种意义上讲,STL的概念和面向对象编程(OOP)的最初思想是矛盾的。这么做的原因是追究更大的灵活性和弹性。STL是泛型编程的一个杰出范例。

15、容器

       文档详细。

16、关于前置式递增/减和后置式递增/减的效率问题:前置式递增/减效率更高,因为后置式递增/减需要一个额外的临时对象。因此建议优先使用前置式递增/减操作符。

17、算法(Algorithms)

       魅力无穷,多多尝试,渐渐熟悉。

18、算法 vs 成员函数

就算我们符合种种条件,得以使用某个算法,那也不一定就合适。容器本身可能提供功能相似且性能更佳的成员函数。当然,凡事都有利弊。

利:性能优良。

弊:由于使用了特定容器的特定成员函数。因此,以后如果想换用另一种容器,就不得不改动程序代码。

在我看来,这个弊端给程序员带来的危害很小,因为一旦更换容器,编译器会告诉我们那些代码(接口)需要更改。因此,应该优先使用成员函数——这是做出不必要的劣化。

19、自定义泛型函数(User-Defined Generic Functions)

为了在这些操作之中声明有效的迭代器,我们必须使用容器提供的类型,因为每一种容器都有自己的迭代器。为了让我们方便写出真正的泛型函数,每一种容器都提供了一些内部类型定义。

20、判断式(Predicates, 谓词)

所谓Predicates,就是返回布尔值(boolean)的函数。他们通常被用来指定排序准则和搜寻准则。Predicates可能有一个或两个操作数,视具体情况而定。注意,并非任何返回布尔值的一元函数或二元函数就是合法的Predicates。STL要求,面对相同的输入值,Predicates必须得出相同的结果。这条戒律将那些“被调用时会改变自己内部状态”的函数清除出场。

21、关于计算绝对值函数 abs()

1、C++98

#include <cstdlib>  /* abs */

     int abs (     int n);
long int abs (long int n);

#include <cmath>        // std::abs
     double abs (double x);
      float abs (float x);
long double abs (long double x);
 double fabs (double x);
      float fabs (float x);
long double fabs (long double x);
此外,还有 
#include <stdlib.h>     /* labs */
long int labs (long int n);
这么多的*abs(), 不明究里。
不过,我们需要知道, 对于*abs()不同的重载形式和函数前面,其位于不同的头文件中。

22、仿函数
       通常的说,仿函数比函数具有更普遍的适用性和诸多优点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值