catalog
map/unordered_map的下标操作
template< _KeyType, _MappedType>
class [unordered_]map{
_MappedType & operator[]( const _KeyType & _k){
iterator i = find( _k);
if( i == end())
i = mp.insert( {_k, _MappedType()});
return (*i).second;
}
}
[unordered_]map< int, Foo> mp
mp[ 1] = Foo()
此时, &mp[ 1]
就是mp里元素的地址!!!
&mp[ 0]
他会, 往mp里, 插入一个{0, Foo()}
-------------------------------
介绍
C++ Standard Lib: 标准库
Standard Template Lib: 标准'模板'库
标准库 > STL, 但STL占据C++标准库的80%
只要有”编译器",就一定自带有”C++标准库“
C++标准库,是以”header头文件“的形式存在
标准库里的东西,都被放在 ”std“这个命名空间里。
不管是什么编译器gnu/vc,他们肯定会自带C++标准库
对标准库的使用,几乎100%是一样的。
学习网站
http://cplusplus.com/
https://en.cppreference.com/w/
https://gcc.gnu.org/onlinedocs/
STL
介绍
STL的6大部件:
1,容器 (重要)
2,算法 (重要)
3,分配器
4,迭代器
5,适配器
6,仿函数
仿函数
一元函数unary_function
template<typename _Arg, typename _Result>
struct unary_function
{
typedef _Arg argument_type;
typedef _Result result_type;
};
' 形如: _Result r = func( a ); '
' 这个类,是基类。 仅仅规范了, 返回值 和 参数 的类型!! '
' 具体,这个func怎么设计, 由子类完成 '
二元函数binary_function
template<typename _Arg1, typename _Arg2, typename _Result>
struct binary_function
{
typedef _Arg1 first_argument_type;
typedef _Arg2 second_argument_type;
typedef _Result result_type;
};
' 形如: _Result r = func( a, b ); '
plus
template<typename _Tp = void>
struct plus;
template<typename _Tp>
struct plus : public binary_function<_Tp, _Tp, _Tp>
{ ' 继承自binary_func,即由2个参数 + 1个返回值 组成 '
_GLIBCXX14_CONSTEXPR
_Tp operator()(const _Tp& __x, const _Tp& __y) const
{ return __x + __y; }
};
int ret = plus<int>()(3, 4);
' 不要写成: plus<int>(3, 4),这是在调用构造函数!!! '
上述代码等价于:
plus<int> obj;
int ret = obj(3, 4);
negate
template<typename _Tp = void>
struct negate;
template<typename _Tp>
struct negate : public unary_function<_Tp, _Tp>
{ ' 继承自unary_,即由1个参数 + 1个返回值 组成 '
_GLIBCXX14_CONSTEXPR
_Tp
operator()(const _Tp& __x) const
{ return -__x; }
};
int ret = negate<int>()(5); ' 不要忘记前面的(),是在构造一个对象 '
less
template<typename _Tp = void>
struct less;
template<typename _Tp>
struct less : public binary_function<_Tp, _Tp, bool>
{
_GLIBCXX14_CONSTEXPR
bool
operator()(const _Tp& __x, const _Tp& __y) const
{ return __x < __y; }
};
' heap就默认使用的这个less, 2个参数(a, b): heap.top是其中的b!! '
适配器
函数适配器bind2nd
bind2nd的作用:
我们已经写好了less这个仿函数,即less(a, b){ return a < b; }
但是,如果说我们想要让 a或b,是一个常数固定值,而不是一个变量。
比如,每次都是less(a, 10):
此时,这个函数,变成只有1个变量!!!
原来他是2元函数,现在变成了1元函数!!!
即,从binary_func -> unary_func 的转换(适配)。
template<typename _Operation, typename _Tp>
binder2nd<_Operation>
bind2nd(const _Operation& __fn, const _Tp& __x)
{
typedef typename _Operation::second_argument_type _Arg2_type;
return binder2nd<_Operation>(__fn, _Arg2_type(__x));
}
1, bind2nd是个函数!!! 它可以模板参数推演,可以不写模板
即” 适配器 ” 是个 函数!!! “仿函数”是个类!!!
2, 他默认你传入的_Operation这个”类型“,是继承自binary_function的
因为只有继承自binary_function,他才有second_argument_type这个typedef
3, 他的返回值 是一个”对象“
4, 使用: bind2nd<类型, 类型>( 对象, 对象 );
__fn是一个对象!! 即一个仿函数的对象。
再看,这个返回值,binder2nd:
template<typename _Operation>
class binder2nd
: public unary_function<typename _Operation::first_argument_type,
typename _Operation::result_type>
{ ' 他是个类(即,仿函数),因为第二参数固定了,所以是一元函数 '
protected:
_Operation op; ' _Operation即是”你原来的 二元函数“ '
typename _Operation::second_argument_type value;
' op 和 value,这是2个对象。 对应构造函数传入的2个参数 '
public:
binder2nd(const _Operation& __x,
const typename _Operation::second_argument_type& __y)
: op(__x), value(__y) { } ' 构造函数 '
typename _Operation::result_type
operator()(const typename _Operation::first_argument_type& __x) const
{ return op(__x, value); }
' 仿函数: 他只需要1个参数!!! 即1个变量,每次和value这固定值 比较 '
' 比较的策略, 即是你原来的2元函数op '
' 这个op(a, b),就是在调用: op这个类里的 对()的操作符重载,即”仿函数" '
less<int> obj;
binder2nd< less<int> > ret = bind2nd< less<int>, int >( obj, 6 );
int ans = count_if( VE_ALL(A) , ret );
' ans 为,A中 所有 < 6 的元素个数。 '
allocator源码
template<typename _Tp>
class allocator: public __allocator_base<_Tp>
{
allocator() throw() { }
}
' 可以看出,allocator这个类的使用 很简单,只是构造一个对象而已 '
即: allocator<int> obj;
' 关键是要看,他的父类 __allocator_base '
namespace std
{
template<typename _Tp>
using __allocator_base = __gnu_cxx::new_allocator<_Tp>;
} ' 即默认的allocator,使用的是: new_allocator '
template<typename _Tp>
class new_allocator
{
new_allocator() { }
size_t max_size() const { return size_t(-1) / sizeof(_Tp); }
' size_t(-1) = 2^32 - 1 '
_Tp* allocate(size_type __n, const void* = 0)
{
if (__n > this->max_size()) std::__throw_bad_alloc();
return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
}
void deallocate(pointer __p, size_t){ ::operator delete(__p); }
' 虽然第二参数没有用到,但是你还需要得填!!! '
}
使用
allocator<int> alloc;
int* arr = alloc.allocate(10); // arr[0, 9]
alloc.deallocate(arr, 10);
' 我们知道,delete/free时 是不用知道 这个指针 当初是new了几个 '
直接free这个指针即可,delete arr,并不需要知道该指针当初new了几个
但是deallocate却需要我们去记忆 你当初是申请了几个元素
' 这太麻烦了, 谁能记得住..... '
所以说明, 并不建议 直接使用allocator来申请内存!!!
他是配合“容器”来使用的