.h
.h
,旧式的C头文件仍要使用.h
std
中STL的六大部件
STL思想:将数据和算法分离,算法借助迭代器进行对于容器的数据进行操作
前闭后开 :容器中begin指向第一个元素,而end指向最后一个元素的下一个元素首地址,所以对于解引用end得到的元素通常是无意义的
C++11的容器遍历语法
for( auto 遍历指针 : 容器 ){// 指针类型是容器元素的类型,auto可以自动推导
// 每次循环指针依次获取容器内的一个元素
}
// auto的使用的前提是你必须知道该声明变量的类型
容器的结构与分类
顺序容器
关系容器
Set/Multiset:每个节点不区分键值,Multi表示主键可以重复
Map/Multimap:每个节点包含一个key和一到多个value,常用红黑树
注:红黑树是自平衡二叉查找树
关联式容器
每一段功能代码使用namespace进行包含,namespace上面声明其需要的库文件
可拓展的容器存在空间利用率降低的问题
STL中的stack和queue是借用容器的一种适配器结构
通常来说,容器自身的属性函数调用运行时间比标准库中的全局函数快
STL模板算法示例
// 算法accumulate,对某个区间的值进行指定运算
template < class InputIterator,
class T,
class BinaryOperation>
T accumulate( InputIterator first,
InputIterator last,
T init,
BinaryOperation binary_op)
{
for(;first!= last; ++first)
// 将元素值累加到初值init上
init = binary_op(init, *first);// 每次调用func函数
return init;
}
// 功能函数
int myfunc(int x, int y){return x+2*y}
//函数雕调用
void test_accumulate(){
int init = 100;
int nums = {1, 2, 3};
accumulate(nums, nums+3, init, myfunc);// 220
}
// for_each算法:对区间的每个元素做指定的事情
template
Function for_each(InputIterator first, InputIterator last,
Function f){
for(;first != last; ++first)
f(*first);
return f;
}
// 函数式功能调用
void myfunc(int i){cout << '' << i;}
// 对象式调用,进行了操作符的重载
struct myclass{
void operator(int i){cout << '' << i;}
}myobj;
void test_for_each(){
vector myvec;
myvec.push_back(10);
myvec.push_back(20);
myvec.push_back(30);
// 下面两个模板调用均输出:10,20,30
for_each(myvec.begin(), myvec.end(), myfunc);
for_each(myvec.begin(), myvec.end(), myobj);
}
// replace算法:范围内所有等于old_value者都以new_value取代
template
void replace(ForwardIterator first,
ForwardIterator last,
const T& old_value,
const T& new_value)
{
for(;first != last; ++first)
if(*first == old_value)
*first = new_value;
}
// count_if算法:可以对指定区间内的每个元素进行条件函数判断,复合的才计数
// 该算法式泛化的,在无序容器中有其特化的cout成员函数
template
typename iterator_traits::difference_type
count_if(InputIterator first, InputIterator last, Predicate pred){
typename iterator_traits::difference_type n = 0;
for(; first != last; ++first)// 区间遍历
if(pred(*first))// 将元素带入条件判断式为真
++n;
return n;
}
// find算法:对区间内的值进行顺序查找
template
InputIterator find (InputIterator first, InputIteratro last, 4
const T& value)
{
while(first != last && *first != value)
++first;
return first;
}
// binary_search算法:在已排序的容器中进行二分查找
// lower_bound:在区间内适合值存放的低地址安插val
template
ForwardIterator lower_bound(ForwardIterator first,
forwardIterator last,
const T& val)
{
ForwardIterator it;
iterator_traits::difference_type count,step;
count = distance(first, last);
while(count > 0){
it = first;
step = count / 2;
advance(it, strp);// 前进步数
if(*it < val){
first = ++it;
count -= step++;
}else
count = step;
}
return first;
}
// binary_search实际调用的是lower_bound函数
template
bool binary_search(ForwardIterator first,
ForwardIterator last,
const T& val)
{
first = std::lower_bound(first, last, val);
return (first != last; && !(val < *first));
}
直接使用分配器,在free空间的时候,需要与申请空间大小相同,所以不直接使用
小的内存空间使用new和delete,大的内存空间使用容器进行
标准库中的源代码是一个宝库
VC6下,分配器allocator类方法内有allocate和deallocate,分别包含operator new ()
和operator delete ()
,而operator new ()
会调用malloc()
进行内存的分配。operator delete ()
调用free()
malloc分配的内存通常更大一些,还有在头尾附加的cookie和尾部附加的padding,所以不要经常使用小块内存多次申请
使用分配器申请512个int类型
// 通常由容器进行调用分配器的函数,如果个人调用,那么容易忘记内存空间的大小
int *p = allocate().allocate(512,(int*)0);// 使用临时对象进行内存的分配
allocator().deallocate(p, 512);// 使用临时对象进行内存的销毁
G2.9中aloc容器的元素大小会被调整到8的倍数,使用数组链进行,数组内一次挂载8的倍数的内存开销,避免了cookie的开销
标准库中更多的是复合关系,而不是继承。继承和复合都可以实现A使用B的功能
迭代器iterator是算法和容器的桥梁
迭代器要定义的五种类型,回应算法的需求
指针是一种native pointer,一种退化的interator
解决计算机问题的尚方宝剑:加一个中间层。
例如native pointer无法进行type提取的问题,使用一个中间层萃取机iterator Traits通过偏特化进行实现
list使用的分配器默认是alloc,使用递增数组链进行内存管理
32位电脑上一个指针是四个字节
list容器中的链表结构体是一个环状的双向链表,有额外的开销
// 库文件的设计是一种更高的抽象
template
// 这种设计不够好,转型需要额外操作
struct __list_node{
typedef void *void_pointer;// 定义泛型,实际使用需要进行转型
void_pointer prev;
void_pointer next;
T data;
};
// 新设计
struct _List_node_base{
_List_node_base* _M_next;
_List_node_base* _M_prev;
};
template
struct _List_node
:public _List_node_base{_Tp _M_data;};
容器中iterator的作用是指向一个元素,并可以通过++指向下一个元素
所有的容器(处理voctor和array),iterator都是一个将其模拟为特定smart pointer的类,可以自动找到下一个容器元素的地址
template
struct __list_iterator{
// 迭代器至少定义的五种类型
typedef __list_iterator self;
typedef bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef __list_node* link_type;
typedef ptrdiff_t difference_type;
// 使用运算符重载实现智能指针
link_type node;
reference operator*() const {return (*node),data;}
pointer operator->() const {return &(operator*());}
// 前++没有参数,使用调用对象
self& operator++(){
node = (link_type)((*node).next);// 取next指针设置为自身
return *this;
}
// 后++有参数,c++规定后++不能连续两次,所以不使用reference(引用)
self operator++(int){
self tmp = *this;// 记录原值,不会调用operator*而是调用拷贝构造
++*this;// 执行操作
return tmp;// 返回原值
}
···
}
容器的设计都要前闭后开,所以list的设计中将最后一个元素设计为不属于该容器的元素
vector容器,每次空间不够扩充时,就到内存中寻找一个与前一段空间相比两倍大小的空间作为扩充空间,将原数据拷贝到前半段,即每次成长需要调用拷贝构造函数和析构函数
array容器必须指定大小,不可扩充
所有的容器几乎都含有两个iterator分别表示首和尾,iterator通常是属性指针组合的一个数据结构
typeid可以打印容器的类型的名称,必须包含#include
deque容器
基本容器的关系
关联式容器类似于一个小型数据库,查找速度快,即可以使用key查找value
红黑树特点
map允许元素的data改变,但是元素的key不可改变
key和data合起来是value
rb_tree提供两种insertion操作
set和mutiset的特点
都以rb_tree为底层的结构,进行++ite可以获得排序,value和key是合二为一的
set指元素的key不可重复,mutiset指元素的key可以重复
不能通过iterator进行元素值的更改(通过const_iterator )
可以看作一个容器的适配器,所有实际操作都是调用底层红黑树进行实现
map和multimap类似,唯一的不同是value表示的是key和data(禁止改key而允许改data)
// 代码原理
template< class Key,
class T,
class Compare = less,
class Alloc = alloc
>
class map{
typedef Key key_type;
typedef T data_type;
typedef pair value_type;// key为const不可改
//底层实现
typedef rb_tree,
key_compare, Alloc> rep_Type;
···
}
map独有的[]
操作符:如果存在key则返回所表示的data,如果不存在则创建
针对同一个操作的不同使用对象提供泛化和特化,泛化适用于该类对象,特化适用于某个对象,并且特化通常效率高。泛化和特化智能的找到效率最高的处理方法
使用一个统一的可量化的标准对一堆对象进行存放并索引
hashtable的特点
标准库中没有提供C++的string的hashFcn
hash容器中数组元素个数一定大于实际使用的元素个数
代码构造
// HashFcn表示对象到特定编号的映射函数,标准是碰撞尽量少
// ExteactKey表示从value中提取key的方法
// EqualKey表示如何进行key值的比较
template< class Value, class Key, class HashFcn, class ExtractKey,
class EqualKey, class Alloc = alloc>
容器大小
C++11中所有的hash容器改名为unordered容器
迭代器是容器和算法的中间层,用于屏蔽容器细节向算法提供服务
// 算法的模板
template
Algorithm(Iterator itr1, Iterator itr2)
{
···
}
迭代器属性iterator_category的继承
template< typename _Category,
typename _Tp,
typename _Distance = ptrdiff_t,
typename _Potinter = _Tp*,
typename _Reference = _Tp&
>
struct iterator
{
typedef _Category iterator_category;
typedef _Tp value_type;
typedef _Distance difference_type;
typedef _Pointer pointer;
typedef _Reference reference;
};
template< typename _Tp,
typename _CharT = char,
typename _Traits = char_traits<_CharT>
>class ostream_iterator
:public itereator
算法需要知道迭代器的分类iterator_category
逆向迭代器reverse iterator
// rbegin和区间的end地址相同
reverse_iterator rbegin(){
return reverse_iterator(end());
}
// rend和区间的begin地址相同
reverse_iterator rend(){
return reverse_iterator(begin());
}
STL规定每个Adaptable Function都要挑选合适的模板继承,因为适配器可以进行修改函数的修改,而修改过程需要对于typedef定义的参数进行提问
// 一个操作数的模板
template
struct binary_function{
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
};
// 两个操作数的模板
template
struct binary_function{
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
};
几个仿函数
// struct;定义的类默认成员访问级别为private
// 类后的冒号表示继承关系
// 算术类Arithmetic
template
struct plus :public binary_function{
T operator()(const T& x, const T& y)const
{return x+y;}
};
template
struct minus:public binary_function{
T operator()(const T& x, const T& y)const
{return x-y;}
};
// 逻辑运算类Logical
template
struct logical_and:public binary_function{
bool operator()(const T& x, const T& y)const
{return x&&y;}
};
// 相对关系类Relatioinal
template
struct equal_to:public binary_function{
bool operator()(const T& x, const T& y)const
{return x == y;}
};
template
struct less:public binary_function{
bool operator()(const T &x, const T &y)const
{return x < y;}
};
比大小的应用
// 默认方式
sort(myvec.begin(), myvec.end());
// 使用函数形式
bool myfunc(int i, int j){return (i
struct less:public binary_function{
bool operator()(const T &x, const T &y)const
{return x < y;}
};
sort(myvec.begin(), myvec.end(), less());
Adapters的作用是将存在的功能进行改造一下
适配器的类型(表示改造对应内含实体的功能)
容器适配器:改造容器的功能
template >
class stack{
···
public:
typedef typename Sequence::value_type value_type;
typedef typename Sequence::size_type size_type;
typedef typename Sequence::referrnce reference;
typedef typename Sequence::const_reference const_reference;
// typename用于帮助编译器进行自动类型推导
protected:
Sequence c;
// 只开放了六个容器的功能,并进行名称的改造
public:
bool empty()const{return c.empty();}
size_type size() const {return c.size();}
reference top(){return c.back();}
const_reference top() const{return c.back();}
void push(const value_type &x){c.push_back(x);}
void pop(){c.pop_back();}
};
c++的编译器可以进行做实参的推导
适配器可以对于一个源代码进行不断的装甲,使得其可以完成不同的功能
C++11增加的适配器bind,可以绑定的
_数字
表示一个占位符,需要添加using namespace std::placeholders
bind的用法
using namespace std::placeholders
// 函数的绑定
double my_divide(double x, double y){return x / y;}
// 直接绑定
auto fn_five = bind(my_divide, 10, 2);
cout << fn_five() << '\n';
// 含一个占位符的绑定
auto fn_five = bind(my_divide, _1, 2);
cout << fn_five(10)<< '\n';
// 含两个占位符的绑定,_1表示调用绑定函数时候的第一个参数
auto fn_five = bind(my_divide, _1, _2);
cout << fn_five(10, 2) << '\n';
// 含占位符并指定返回类型的绑定
auto fn_rounding = bind(my_divide, _1, _2);
cout << fn_rounding(10, 3) << '\n';
// 成员的绑定
Mypair ten_two {10, 2};
// 直接绑定
auto bound_memfn = bind(&MyPair::a, ten_two);
cout << bound_memdata();
// 含成员的绑定
auto bound_memfn = bind(&MyPair::multiply, _1);
cout << bound_memfn(ten_two) << '\n';
模板的使用后,编程出现一个错误可能会很多行的全局错误
OOP是数据和操作方法放在同一个类中,GP是将数据和操作方法分离
GP可以使得算法和容器团队分开各自工作,只要规范接口即可
不可重载的四个运算符. .* :: ?:
C++中tuple的使用
// 使用的多参数可变技术:可以将n个参数分解为最后一个和剩余部分(递归到最后一个)
templateclass tuple;
template<>class tuple<>{};// 递归终止的偏特化
template
class tuple// 类的递归
:private tuple
{
typedef tuple inherited;
public:
tuple(){}
tuple(Head v, Tail... vtail)
:m_head(v), inherited(vtail...){}
typename Head::type head(){return m_head;}
inherited& tail(){return *this;}
protected:
Head m_head;
};
tuple t1(1, 1.0, "aa")// 定义方式
auto t2 = make_tuple(22, 44, "ss");// 定义方式2
cout << "t1:"<(t1) << '' << get<1>(t1) << get<2>(t1);// 输出
get<1>(t1) = get<1>(t2);// 取值并赋值
// 多参数可变的应用
t1.head();// 值为1
t1.tail().head();// 值为1.0
// 解耦合
int i;
float f;
string s;
tie(i, f, s) = t1;// 将t1元素解耦合赋值给不同变量
type traits的泛化和特化
// 可以了解自定义或库中类所能支持的功能
// 泛化
template
struct __type_traits{
// true 和 false 表示该标志是否重要
typedef __true_type this_dummy_member_must_be_first;
typedef __false_type has_trivial_default_constructor;
typedef __false_type has_trivial_copy_constructor;
typedef __false_type has_trivial_assignment_operator;
typedef __false_type has_trivial_destructor;
typedef __false_type is_POD_type;
};
// 偏特化
struct __type_traits {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
struct __type_traits {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
// 算法对于typedef标志定义的询问
__type_traits::has_trivial_destructor
一个类只要在作为基类时,才可能是virture
cout是一个对象,内含对<<
操作符的重载
moveable对于扩充型容器可以极大的提高速度,因为它在容器的扩充中只拷贝指针
深拷贝:不但把指针进行拷贝,指针指向的内容也进行拷贝。浅拷贝很危险
栈容器的使用https://blog.csdn.net/gongkeguo/article/details/122049270