auto_ptr
模板定义了类似指针的对象,是一种智能指针,当auto_ptr对象过期时,其析构函数将使用delete来释放内存。
void test1()
{
int* ip = new int(10); //动态内存未释放
return;
}
void test2()
{
auto_ptr ip(new int(10)); //auto_ptr对象过期后,会释放动态内存
return;
}
注意,只能对new分配的内存使用auto_ptr对象,而不要对由new[]分配的或通过声明变量分配的内存使用它。
STL
提供了一组表示容器、迭代器、函数对象和算法的模板。
STL
是一种通用编程技术,模板提供了存储在容器中的数据类型的通用表示,迭代器则是遍历容器中的值的通用表示。
容器概念描述了所有容器类都通用的元素,换句话说,容器概念指定了所有STL容器类都必须满足的一系列要求。
可以通过添加要求来改进基本的容器概念。
各种容器模板都接受一个可选的模板参数,该参数指定使用哪个分配器对象来管理内存,例如vector模板:
template
> class vector : protected _Vector_base<_Tp, _Alloc> {…}
deque、list、queue、priority_queue、stack 和 vector 都是序列类型容器。
序列(sequence)概念增加了迭代器至少是正向迭代器的要求,以保证元素按特定的顺序排列,不会在两次迭代之间发生变化。
set、multiset、map 和 multimap 都是联合类型容器。
联合容器将值与关键字关联在一起,使用关键字来查找值。
STL定义了5种迭代器——输入迭代器、输出迭代器、正向迭代器、双向迭代器、随机访问迭代器。
为何需要这么多迭代器呢?目的是为了在编写算法时尽可能使用要求最低的迭代器,并让它适用于容器的最大区间。
STL根据所需的迭代器类型对算法进行了描述,例如 find() 的原型指出,这种算法需要一个输入迭代器。
template
InputIterator find (InputIterator first, InputIterator last, const T& value);
迭代器是广义指针,而指针满足所有的迭代器要求,因此STL算法可以使用指针来对基于指针的非STL容器进行操作。
例如,使用 sort() 对数组进行排序:
double nums[10];
sort(nums, nums + 10);
头文件
很多STL算法都使用函数对象——也叫函数符(functor)。函数符是可以以函数方式与()结合使用的任意对象,这包括函数名、指向函数的指针和重载了()操作符的类对象(即定义了函数operator()()的类)。
STL也定义了函数符概念:
对应的改进版概念:
例如, sort() 函数可以将二元断言作为其第3个参数:
bool Compare(const Book& book1, const Book& books);
...
sort(books.begin(), books.end(), Compare);
为了支持将函数作为参数的STL函数,STL定义了多个基本函数符,它们执行诸如将两个值相加、比较两个值是否相等操作。
例如,假设需要对两个数组进行相加,普通实现和使用预定义函数符的实现为:
#include
#include
#include
#include
#include
using namespace std;
double add(double d1, double d2) { return d1 + d2; }
int main()
{
ostream_iterator out(cout, " ");
vector ds1 = { 1.1, 2.2, 3.3, 4.4 };
vector ds2 = { 1, 2, 3, 4 };
// 1、普通实现必须为每种类型单独定义一个函数
transform(ds1.begin(), ds1.end(), ds2.begin(), out, add);
cout << endl;
// 2、更好的办法是定义一个模板,而STL就已经预定义好了这么一个模板
plus add2;
transform(ds1.begin(), ds1.end(), ds2.begin(), out, add2);
}
如果 STL 函数需要一个一元函数,而现有一个能完成相应工作的自适应二元函数,则可以使用 bind1st 或 bind2nd 使该二元函数适应于一元接口。
#include
#include
#include
#include
#include
#include
using namespace std;
double sqrt(double d1) { return d1 * 2.5; }
int main()
{
ostream_iterator out(cout, " ");
vector ds1 = { 1.1, 2.2, 3.3, 4.4 };
// 1、普通实现
transform(ds1.begin(), ds1.end(), out, sqrt);
cout << endl;
// 2、另外一种实现是,将现有能实现该功能的二元函数适配为一元函数
transform(ds1.begin(), ds1.end(), out, binder1st>(multiplies(), 2.5));
}
对于算法函数设计,有两个主要的通用部分。首先,它们都使用模板来提供通用类型;其次,它们都使用迭代器来提供访问容器中数据的通用表示。
STL 将算法库分为4组:
相较于 STL 函数,STL 方法通常是更好的选择。首先,它更适合于特定的容器;其次,作为成员函数,它可以使用模板类的内存管理工具从而在需要时调整容器的长度。
Complex 头文件为复数提供了一个 complex 类模板,专用于 float、long 和 long double。
valarray 头文件提供了 valarray 模板类,被设计成用于表示数值数组,支持各种数值数组操作。