# 概述
算法中包含很多对容器进行处理的算法,使用迭代器来标识要处理的数据或数据段、以及结果的存放位 置,有的函数还作为对象参数传递给另一个函数,实现数据的处理。这些算法可以操作在多种容器类型 上,所以称为 “泛型”,泛型算法不是针对容器编写,而只是单独依赖迭代器和迭代器操作实现。而且算法 库中的算法都是普通函数(自由函数)。
# 算法的分类
- 非修改式的算法:
for_each、count、find - 修改式的算法:
copy、remove、remove_if、replace - 排序算法:
sort - 二分搜索算法:
lower_bound - 集合操作:
set_intersection - 堆操作:
make_heap、push_heap、pop_heap - 取最大值最小值:
max、min - 数值操作:
accumulate - 未初始化的内存操作:
uninitialized_copy
# 一元函数以及一元断言 / 一元谓词
- 一元函数:函数的参数只有一个;
- 一元断言 / 一元谓词:函数的参数只有一个,并且返回类型是
bool类型。 - 二元函数:函数的参数有两个;
- 二元断言 / 二元谓词:函数的参数两个,并且返回类型是
bool类型。
# 非修改式算法 for_each


// # if __cplusplus > 201703L | |
// # define _GLIBCXX20_CONSTEXPR constexpr | |
/** | |
* @brief Apply a function to every element of a sequence. | |
* @ingroup non_mutating_algorithms | |
* @param __first An input iterator. | |
* @param __last An input iterator. | |
* @param __f A unary function object. | |
* @return @p __f | |
* | |
* Applies the function object @p __f to each element in the range | |
* @p [first,last). @p __f must not modify the order of the sequence. | |
* If @p __f has a return value it is ignored. | |
*/ | |
template<typename _InputIterator, typename _Function> | |
_GLIBCXX20_CONSTEXPR | |
_Function | |
for_each(_InputIterator __first, _InputIterator __last, _Function __f) | |
{ | |
// concept requirements | |
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) | |
__glibcxx_requires_valid_range(__first, __last); | |
for (; __first != __last; ++__first) | |
__f(*__first); | |
return __f; // N.B. [alg.foreach] says std::move(f) but it's redundant. | |
} |
for_each(vec.begin(), vec.end(), [](int &value) -> void { | |
++value; | |
cout << value << " "; | |
}); |
# 修改式算法 remove_if


bool func(int value) { | |
return value > 6; | |
} | |
int main() { | |
vector<int> vec = {1, 3, 5, 8, 6, 4, 7, 9}; | |
for_each(vec.begin(), vec.end(), [](int &value) { | |
cout << value << " "; | |
}); | |
cout << endl; | |
// 将所有大于 6 的元素删除 | |
cout << endl << "执行remove_if操作之后" << endl; | |
//remove_if 不能将满足条件的元素直接删除,但是会返回待删除元素的首迭代器 | |
// 然后再配合容器的 erase 操作,才可以达到删除的满足条件的效果 | |
auto it = remove_if(vec.begin(), vec.end(), func); | |
vec.erase(it, vec.end()); | |
for_each(vec.begin(), vec.end(), [](int &value) { | |
cout << value << " "; | |
}); | |
cout << endl; | |
return 0; | |
} |
/** | |
* @brief Remove elements from a sequence using a predicate. | |
* @ingroup mutating_algorithms | |
* @param __first A forward iterator. | |
* @param __last A forward iterator. | |
* @param __pred A predicate. | |
* @return An iterator designating the end of the resulting sequence. | |
* | |
* All elements for which @p __pred returns true are removed from the range | |
* @p [__first,__last). | |
* | |
* remove_if() is stable, so the relative order of elements that are | |
* not removed is unchanged. | |
* | |
* Elements between the end of the resulting sequence and @p __last | |
* are still present, but their value is unspecified. | |
*/ | |
template<typename _ForwardIterator, typename _Predicate> | |
_GLIBCXX20_CONSTEXPR | |
inline _ForwardIterator | |
remove_if(_ForwardIterator __first, _ForwardIterator __last, | |
_Predicate __pred) | |
{ | |
// concept requirements | |
__glibcxx_function_requires(_Mutable_ForwardIteratorConcept<_ForwardIterator>) | |
__glibcxx_function_requires(_UnaryPredicateConcept<_Predicate, typename iterator_traits<_ForwardIterator>::value_type>) | |
__glibcxx_requires_valid_range(__first, __last); | |
return std::__remove_if(__first, __last, | |
__gnu_cxx::__ops::__pred_iter(__pred)); | |
} | |
template<typename _ForwardIterator, typename _Predicate> | |
_GLIBCXX20_CONSTEXPR | |
_ForwardIterator | |
__remove_if(_ForwardIterator __first, _ForwardIterator __last _Predicate __pred) | |
{ | |
__first = std::__find_if(__first, __last, __pred); | |
if (__first == __last) | |
return __first; | |
_ForwardIterator __result = __first; | |
++__first; | |
for (; __first != __last; ++__first) | |
if (!__pred(__first)) | |
{ | |
*__result = _GLIBCXX_MOVE(*__first); | |
++__result; | |
} | |
return __result; | |
} |
# vector 的 push_back 操作导致迭代器失效
vector<int> vec; | |
vec.push_back(100); | |
bool flag = true; | |
for (auto it = vec.begin(); it != vec.end(); ++it) { | |
cout << *it << " ";// 读 | |
if (flag) { | |
// 在执行 push_back 的时候,底层已经发生了扩容,导致迭代器 | |
//it 指向的还是老的空间,所以此时迭代器已经失效了 | |
// 解决方案:重置迭代器的位置(更新迭代器) | |
vec.push_back(200);// 写 | |
it = vec.begin();// 更新迭代器 | |
flag = false; | |
} | |
} | |
cout << endl; |
# bind1st 与 bind2nd

对于二元断言 Func 而言如果现在可以固定第过个参数 Args2 ,将其固定为 6,那么此处要想删除大于 6 的元素,那么 Func 的实现就是 Args1 > 6 ,也就表明 Func 具备大于符号的含义,也就是 std:: greater ;
如果现在可以固定第一个参数 Args1 ,将其固定为 6,那么此处要想删除大于 6 的元素,那么 Func 的实现就是 6 > Args2 , 也就表明 Func 具备小于符号的含义,也就是 std:: less ;

bind1st 可以固定二元函数对象 f 的第一个参数,将其固定为 x
bind2nd 可以固定二元函数对象 f 的第二个参数,将其固定为 x
// 将所有大于 6 的元素删除 | |
cout << endl << "执行 remove_if 操作之后" << endl; | |
auto it = remove_if(vec.begin(), vec.end(), bind2nd(std::greater<int>(), 6)); |
bind2nd 绑定了二元函数对象 std::greater 的右操作数 rhs = 6 , 而 greater 的实现是 return lhs > rhs = 6 ,也就是将大于 6 的删除。
# bind
# 模板形式



# 绑定函数的类型
int add(int x, int y) { | |
cout << "int add(int, int)" << endl; | |
return x + y; | |
} | |
int multiply(int x, int y, int z) { | |
cout << "int multiply(int, int, int)" << endl; | |
return x * y * z; | |
} | |
class Example { | |
public: | |
// Example * const this | |
int add(/* this */int x, int y) { | |
cout << "int Example::add(int, int)" << endl; | |
return x + y; | |
} | |
}; | |
int main(int argc, char *argv[]) { | |
// 绑定普通的二元函数 | |
auto f = bind(&add, 1, 2); | |
cout << "f() = " << f() << endl; | |
// f() = int add(int, int) 3 | |
cout << endl << endl; | |
// 绑定普通的三元函数 | |
auto f2 = bind(&multiply, 3, 4, 5); | |
cout << "f2() = " << f2() << endl; | |
// f2() = int multiply(int, int, int) 60 | |
cout << endl << endl; | |
Example ex; | |
// 绑定成员函数,但是非静态成员 | |
// 函数的 this 指针不要忘了 | |
auto f3 = bind(&Example::add, &ex, 10, 30); | |
cout << "f3() = " << f3() << endl; | |
// f3() = int Example::add(int, int) 40 | |
return 0; | |
} |
# 引用折叠
引用折叠(reference collapsing)是指在模板编程中,编译器如何处理嵌套的模板参数引用的情况。引用折叠允许通过一系列引用来访问模板参数的类型,即使这些引用是嵌套的。
在 C++11 及以后的版本中,引入了引用折叠的规则,以便在模板参数中使用引用时,能够简化类型表达式。引用折叠主要发生在以下几种情况:
T&和T&:如果两个引用类型相同,它们会折叠成单个引用。T& & -> T&T&和T&&:左值引用和右值引用相遇时,右值引用会被转换为左值引用。T& && -> T&T&&和T&:右值引用和左值引用相遇时,左值引用会被忽略。T& && -> T&T&&和T&&:两个右值引用相遇时,它们会折叠成单个右值引用。T&& && -> T&&
这些规则在模板参数推导时非常有用,因为它们允许编译器正确地推导出模板参数的类型,即使这些类型是通过引用传递的。
# 函数指针
/* func1(); */ | |
// 函数指针的定义形式 | |
//typedef int (*)() pFunc; //error, 语法是错的 | |
typedef int(*pFunc)(); //ok,C 语言的写法 | |
//using pFunc = int (*)(); //ok,C++11 的 | |
// typedef int A; | |
// using A = int; | |
// 回调函数是被动调用的,会先注册给函数指针,然后由函数指针进行调用 | |
// 函数指针可以将指向的回调函数延迟调用 | |
pFunc f = &func1; // 回调函数的注册 | |
cout << "111-11" << endl; | |
cout << "f() = " << f() << endl; // 回调函数的执行 | |
cout << endl; | |
pFunc f2 = func2; | |
cout << "f2() = " << f2() << endl; | |
cout << endl; | |
// 函数的指针的类型不匹配,所以就不能这么使用 | |
// pFunc f3 = func3; // error | |
return 0; |
# 占位符
void func(int x1, int x2, int x3, const int &x4, int x5) { | |
cout << "x1 = " << x1 << endl | |
<< "x2 = " << x2 << endl | |
<< "x3 = " << x3 << endl | |
<< "x4 = " << x4 << endl | |
<< "x5 = " << x5 << endl; | |
} | |
int main(int argc, char *argv[]) { | |
int number = 100; | |
// 占位符整体代表的是形参的位置 | |
// 占位符中的数字代表的是实参的位置 | |
// 实参的个数一定要大于等于占位符中数字的最大值 | |
//bind 的默认采用值传递 | |
// 引用的包装器 std::ref = reference | |
// 引用的包装器 std::cref = const reference | |
using namespace std::placeholders; | |
auto f = bind(func, 1, _4, _3, std::cref(number), number); | |
number = 200; | |
f(2, 30, 400, 5000, 6666);// 多余的参数直接丢掉 | |
return 0; | |
} |
# function

// 函数形态(类型、标签): 函数的返回类型 + 参数列表 | |
//add 的类型:int (int, int) | |
//f 的类型: int () | |
/* auto f = bind(&add, 1, 2); */ | |
function<int()> f = bind(&add, 1, 2); | |
cout << "f() = " << f() << endl; | |
// f() = int add(int, int) 3 | |
cout << endl << endl; | |
//multiply 的类型:int (int, int, int) | |
//f2 的类型:int () | |
function<int()> f2 = bind(&multiply, 3, 4, 5); | |
cout << "f2() = " << f2() << endl; | |
// f2() = int multiply(int, int, int) 60 | |
/* f = bind(&multiply, 3, 4, 5); */ | |
/* cout << "f() = " << f() << endl; */ |
# 绑定数据成员
class Example { | |
public: | |
int add(/* this */int x, int y) { | |
cout << "int Example::add(int, int)" << endl; | |
return x + y; | |
} | |
int data = 222; | |
}; |
data 是 Example 中的数据成员, bind 还可以绑定数据成员。
将成员的名字看成是函数的名字,数据成员的类型就是函数的返回类型,参数列表就是空(隐含的 this 还是有的)。
cout << endl << "bind 绑定数据成员" << endl; | |
Example ex2; | |
function<int()> f5 = bind(&Example::data, &ex2); | |
cout << "f5() = " << f5() << endl; |
# bind 绑定成员函数传参方式
class Example { | |
public: | |
int add(/* this */int x, int y) { | |
cout << "int Example::add(int, int)" << endl; | |
return x + y; | |
} | |
}; | |
int main() { | |
Example ex; | |
auto f = bind(&Example::add, &ex, 10, 30); // 传地址 | |
cout << "f(&ex) = " << f(&ex) << endl; | |
cout << endl; | |
auto f2 = bind(&Example::add, ex, 100, 300); // 传对象 | |
cout << "f2(ex) = " << f2(ex) << endl; | |
} |
传地址与传对象的区别:对象地址的传递就是一个指针的传递,不会出现拷 贝操作,但是使用对象传递,会存在拷贝对象操作,对象如果占用内存较大,会浪费空间。
使用对象地址,如果在使用的时候,对象已经销毁了,就有空指针的问题,但是拷贝一份对象,那原对象销毁了,这里采用的是拷贝操作,就不会有影响。
# bind 与 function 的结合使用
class Figure { | |
public: | |
// 纯虚函数 | |
virtual void display() const = 0; | |
virtual double area() const = 0; | |
}; | |
class Rectangle: public Figure { | |
public: | |
explicit Rectangle(double length = 0, double width = 0) | |
: _length(length), _width(width) { | |
cout << "Rectangle(double = 0, double = 0)" << endl; | |
} | |
void display() const override { | |
cout << "Rectangle"; | |
} | |
double area() const override { | |
return _length * _width; | |
} | |
~Rectangle() { | |
cout << "~Rectangle()" << endl; | |
} | |
private: | |
double _length; | |
double _width; | |
}; |
面向对象的写法:继承 + 虚函数(纯虚函数),运行时,灵活性强。
基于对象的写法: std:: bind + std:: function , 编译时,效率高。
C 语言中使用函数指针进行注册回调函数与执行回调函数。
C++ 中使用 std:: bind + std:: function 进行注册与执行回调函数。
class Figure { | |
public: | |
// 定义出来了两种类型别名 | |
using DisplayCallback = function<void()>; | |
using AreaCallback = function<double()>; | |
/** | |
* void() | |
* virtual void display() const = 0; | |
* double() | |
* virtual double area() const = 0; | |
* void setDisplayCallback(const DisplayCallback &cb) { | |
* _displayCallback = cb; | |
* } | |
*/ | |
// 回调函数的注册 | |
void setDisplayCallback(DisplayCallback &&cb) { | |
_displayCallback = std::move(cb); | |
} | |
void setAreaCallback(AreaCallback &&cb) { | |
_areaCallback = std::move(cb); | |
} | |
// 回调函数的执行 | |
void handleDisplayCallback() const { | |
if (_displayCallback) { | |
_displayCallback(); | |
} | |
} | |
double handleAreaCallback() const { | |
if (_areaCallback) { | |
return _areaCallback(); | |
} else { | |
return 0.0; | |
} | |
} | |
DisplayCallback _displayCallback; | |
AreaCallback _areaCallback; | |
}; |
class Rectangle: public Figure { | |
public: | |
explicit Rectangle(double length = 0, double width = 0) | |
: _length(length), _width(width) { | |
cout << "Rectangle(double = 0, double = 0)" << endl; | |
} | |
void display() const override { | |
cout << "Rectangle"; | |
} | |
double area() const override { | |
return _length * _width; | |
} | |
~Rectangle() { | |
cout << "~Rectangle()" << endl; | |
} | |
private: | |
double _length; | |
double _width; | |
}; |
class Rectangle { | |
public: | |
explicit Rectangle(double length = 0, double width = 0) : _length(length), _width(width) { | |
cout << "Rectangle(double = 0, double = 0)" << endl; | |
} | |
void display(int x, int y) const { | |
cout << "Rectangle"; | |
} | |
double area() const { | |
return _length * _width; | |
} | |
~Rectangle() { | |
cout << "~Rectangle()" << endl; | |
} | |
private: | |
double _length; | |
double _width; | |
}; |
基于对象的使用:
Rectangle rectangle(10, 20); | |
cout << endl; | |
Figure fig; | |
/* function<void()> f = bind(&Rectangle::display, &rectangle, 1, 2); */ | |
/* fig.setDisplayCallback(std::move(f)); */ | |
fig.setDisplayCallback(bind(&Rectangle::display, &rectangle, 1, 2)); //bind 改变 display 的状态 | |
fig.setAreaCallback(bind(&Rectangle::area, &rectangle)); | |
func(fig); |
# mem_fn 成员函数适配器


class Number { | |
public: | |
Number(size_t data = 0): _data(data) {} | |
void print() const { | |
cout << _data << " "; | |
} | |
// 判断是不是偶数 | |
bool isEven() const { | |
return (0 == _data % 2); | |
} | |
// 判断是不是质数 | |
bool isPrime() const { | |
if (1 == _data) { | |
return false; | |
} | |
for (size_t idx = 2; idx <= _data / 2; ++idx) { | |
if (0 == _data % idx) { | |
return false; | |
} | |
} | |
return true; | |
} | |
~Number() = default; | |
private: | |
size_t _data; | |
}; | |
int main(int argc, char *argv[]) { | |
vector<Number> vec; | |
for (size_t idx = 1; idx != 30; ++idx) { | |
vec.push_back(Number(idx)); | |
} | |
//for_each 与成员函数 print 并不能很好的适配,需要使用 mem_fn 进行适配 | |
for_each(vec.begin(), vec.end(), mem_fn(&Number::print)); | |
cout << endl << endl; | |
auto it = remove_if(vec.begin(), vec.end(), mem_fn(&Number::isEven)); | |
vec.erase(it, vec.end()); | |
for_each(vec.begin(), vec.end(), mem_fn(&Number::print)); | |
cout << endl; | |
// 删除所有的质数 | |
cout << endl << endl; | |
it = remove_if(vec.begin(), vec.end(), mem_fn(&Number::isPrime)); | |
vec.erase(it, vec.end()); | |
for_each(vec.begin(), vec.end(), mem_fn(&Number::print)); | |
cout << endl; | |
return 0; | |
} |
