C++ standard

2021-07-24
10 min read

参考资料:

  1. 《The C++ Standard Library, 2nd Edition》

Tips

  • __cplusplus

  • 统一初始化,不允许 narrowing

    • 花括号优先匹配列表初始化方法 std::initializer_list<>
    • 花括号可以降级为圆括号(P s = {77,5}; ),但可以使用 explicit 禁止

Basic

graph TB
	A[basic]
	B[Techs]
	C[Utils]
	D[RVO]
	E[str encode]
	F[lambd<br/>mutable]
	G[except ptr]
	H[type traits]
	I[true_type]
	J[is_signed]
	K[get]
	M[unary<br/>relation<br/>modify]
	N[std::ref/cref]
	O[parentheses]
	P[smart ptr]
	Q[dtor time]
	
	A-->B
	A-->C
	B-->D
	B-->E
	B-->F
	B-->G
	B-->H
	H-->I
	I-->J
	H-->M
	C-->N
	N-->O
	C-->P
	P-->Q
	N-->K

Techs

返回值优化

满足如下代码形式的函数,C++ 一般默认利用返回值优化或者移动语意来减少拷贝次数

X foo () {
  X x;
  ...
  return x;
}

字符串编码指定

L"hello" // defines ‘‘hello’’ as wchar_t string literal

  1. u8 defines a UTF-8 encoding
  2. u defines a string literal with characters of type char16_t
  3. U defines a string literal with characters of type char32_t
  4. L defines a wide string literal with characters of type wchar_t

Lambda

The type of a lambda is an anonymous function object (or functor) that is unique for each lambda expression

Lambda 的两种定义形式

[...] {...} 
[...] (...) mutableopt throwSpecopt ->retTypeopt {...}

lambda 默认将可调用方法置为 const,且传递的变量与源变量没有关系,lambda 内部活动的值是原变量的快照

int id = 0;
auto f = [id] () mutable {
	std::cout << "id: " << id << std::endl;
	++id; // OK
};

// 上面的 lambda 可以认为是下面的形式
class {
private:
	int id; // copy of outside id
public:
	void operator() () { // 如果没有 mutable,则当前函数为 const 成员函数
		std::cout << "id: " << id << std::endl;
		++id; // OK
	}
};

异常

C++ 中的异常对象可以通过异常指针的形式进行传递

构造与析构的时机

Note that destructors are called only if any construction is completed. So, if an exception occurs inside a constructor, destructors are called only for objects that have been fully constructed. This can result in resource leaks for classes with multiple raw pointers if during the construction the first new was successful but the second was not

Type Traits

部分 typetraits 相关的函数继承 true_type/false_type

示例 is_signed<T>
namespace detail {
	template<typename T,bool = std::is_arithmetic<T>::value>
	struct is_signed : std::integral_constant<bool, T(-1) < T(0)> {};

	template<typename T>
	struct is_signed<T,false> : std::false_type {};
} // namespace detail
 
template<typename T>
struct is_signed : detail::is_signed<T>::type {};
Unary/Relation/Modifier Traits
  1. unary 示例:is_void<T>/is_signed<T> 等等
  2. Relation 示例:is_same<T,D>/is_base_of<T,D > 等等
  3. Modifier 示例:add_const<T>::type/make_signed<T>::type 等等

Utils

graph TB
	A[Utils]
	B[pair<br/>tuple]
	C[get<0>]
	D[std::tie<br/>ignore]
	E[smartptr]
	F[make_*]
	G[deleter]
	H[enable<br/>weak]
	I[Aux]
	J[max<br/>minmax]
	K[cref/cmp]
	L[rel_op]
	M[chrono]
	N[du/tp/ck]
	O[ratio]

	
	A-->B
	B-->C
	B-->D
	A-->E
	E-->F
	E-->G
	E-->H
	A-->I
	I-->J
	J-->K
	I-->L
	A-->M
	M-->N
	M-->O

pair && tuple

  1. pair 可以使用 tuple 的接口
  2. pair 有三种构造函数,前两种常规构造,第三种利用了 std::piecewise_construct 以实现与前两种构造的区分。第三种构造函数用于 first/second 构造需要多个参数的场景
  3. tuple 不支持隐式类型转换
auto t2 = make_tuple(22,44,"nico"); // assign second value in t2 to t1 
get<1>(t1) = get<1>(t2);

typename std::tuple<int,float,std::string> TupleType;
std::tuple_size<TupleType>::value // yields 3 
std::tuple_element<1,TupleType>::type // yields float
get
template< std::size_t I, class... Types >
typename std::tuple_element<I, tuple<Types...> >::type& get( tuple<Types...>& t ) noexcept;
unpack pair/tuple
std::pair<char,char> p=std::make_pair(’x’,’y’);

char c;
std::tie(std::ignore,c) = p; // extract second value into c (ignore first one)

std::ref/std::cref

std::ref 的实现示例信息可参考 https://en.cppreference.com/w/cpp/utility/functional/ref

智能指针

  1. 优先使用 make_shared/make_unique。可以减少内存分配的次数并减少出错的几率
  2. 智能指针本身不是线程安全的,比如 sharedptr 对象一般包含两个指针变量,直接操作指针对象需要加锁
删除器

删除器是 unique_ptr 类型的一部分,但不是 shared_ptr 类型的一部分,二者的定义形式如下:

template< class T > class shared_ptr;

// unique ptr 有数组类型的特例化版本
template<class T, class Deleter = std::default_delete<T> > class unique_ptr;
// 数组特利化 uniqueptr 提供了 [] 操作符重载,但没有 -> 和 *
template<class T, class Deleter> class unique_ptr<T[], Deleter>;

sharedptr 没有数组数据类型的特例化版本,所以使用 sharedptr 保存数组需要提供自定义的删除器

std::shared_ptr<int> p(new int[10], std::default_delete<int[]>());
weak_ptr

weak_ptr 的一个使用示例是 Person,father/mother/children 都是 person,有相互指向的需要

weakptr 有两个功能:

  1. 解决 sharedptr 的循环引用问题
  2. 共享但又不想持有,weak_ptrshared_ptr 有着相同类型的控制块,所以二者之间可以相互转换。也因为这个原因,weak_ptr 的构造函数只接受 shared_ptr

你不能直接使用 weak_ptr,需要先将其转换为 shared_ptr

  1. sharedptr 支持使用 weakptr 构造,如果 weakptr 无效,则抛异常(bad_weak_ptr
  2. 调用 weakptr 的 lock 成员函数,如果无效则返回空的 sharedptr
enable_shared_from_this

enable_shared_from_this 内部一般只有一个 weak_ptr 作为成员变量

当前类除了 shared_from_this 这个方法外,其他方法都是私有的。因为 shared_ptr 是 friend,所以只能使用 make_shared 等与 shared_ptr 相关的方法创建对象

所有与 enable_shared_from_this 相关的构造函数都使用了 type_traits ,以此来实现特殊流程

template<class D>
class enable_shared_from_this {
protected:
    // 注意这里的构造函数是 protected
    constexpr enable_shared_from_this();
    enable_shared_from_this(enable_shared_from_this const&);
    enable_shared_from_this& operator=(enable_shared_from_this const&);

public:
    shared_ptr<T> shared_from_this() { return self_.lock(); }
    shared_ptr<T const> shared_from_this() const { return self_.lock(); }

private:
    weak_ptr<D> self_;
    friend shared_ptr<D>;
};

// 根据 traits 实现的特殊处理
if (std::is_base_of<std::enable_shared_from_this<T>, T>::value) {
	enable_shared_from_this<T>& base = *ptr;
	base.self_ = *this;
}

Numeric Limit

Minimum Size of Built-In Types,可参考:https://en.wikipedia.org/wiki/C_data_types

Auxiliary

min/max/minmax/max_element

Note that the versions taking two values return a const reference; the versions taking initializer lists return copies of the values

namespace std { 
  template <typename T> 
  const T& min (const T& a, const T& b); 
  
  template <typename T> T min (initializer_list<T> initlist);
  
  template< class T>
	std::pair<const T&,const T&> minmax( const T& a, const T& b );
  
  template< class ForwardIt >
	ForwardIt max_element( ForwardIt first, ForwardIt last );
}

min 等函数可以提供自定义的比较方法:max(initlist,cmp) 。如此对于大型对象,可以直接传指针

auto extremes = std::minmax ({px, py, pz}, [](int*a, int*b) { return *a < *b; });
rel_ops

Four function templates define the comparison operators !=, >, <=, and >= by calling the operators == and <

使用 rel_ops ,我们只需要定义类的等于和小于操作即可

#include <utility>
using namespace std::rel_ops; // make !=, >, etc., available

chrono

ratio<T,D>

ratio 模版是编译时工具,标准库中常用于 chrono 库中。ratio 有一些缩写,比如 std::nano 表示1/1000 000 000

namespace std { 
  template <intmax_t N, intmax_t D = 1> 
  class ratio { 
    public: typedef ratio<num,den> type; 
    // gcd 用于求最大公约数
    static constexpr intmax_t num = sign(N) * sign(D) * abs(N) / gcd(N, D);
    static constexpr intmax_t den = abs(D) / gcd(N, D);
  }; 
}

ratio 会自动化简分数(注意化简后符号的位置):

int main() {
    using rat = std::ratio<3,-12>;
    std::cout << rat::num << "/" << rat::den << std::endl;// -1/4
}

ratio 支持编译时计算,比如:ratio_less_equal/ratio_add 等等

system_clock/steady_clock /hi...

注意成员方法 is_steady

Epoch/Durations/Timepoints

Duration:

A duration is a combination of a value representing the number of ticks and a fraction representing the unit in seconds

template<class Rep, class Period = std::ratio<1> > class duration;

std::chrono::duration<int> twentySeconds(20); 
std::chrono::duration<double,std::ratio<60>> halfAMinute(0.5)

因为 ratio 的存在,不容单位的 duration 可以同时进行运算。如果默认转换会丢失信息,比如从分钟转换为小时,此时编译器会报错,但可以使用强制类型转换 duration_cast<T>(...)

Timepoint:

A timepoint is defined as combination of a duration and a beginning of time (the so-called epoch)

Timepoint, is parametrized by a clock, which is the object that defines the epoch of a timepoint

template<class Clock,class Duration = typename Clock::duration> class time_point;

一般而言,timepoint 内部只有一个成员变量

ctime/asctime/to_time_t

STL

graph TB
	A[STL]
	B[Container]
	C[Itr]
	D[Algs]
	E[in/out<br/>Fd-Bi-Rd]
	F[Seq]
	G[Ass]
	H[unorder<br/>unset]
	I[list<br/>array]
	J[set<br/>mset]
	K[bitset]
	L[pos<br/>deps value]
	M[pos no<br/>deps value]
	N[Adapters]
	O[stk/q/pq]
	P[remove<br/>erase]
	Q[begin<br/>end]
	R[find_if<br/>copy]
  S[inserter]
  T[cbegin<br/>rbegin]
  U[it != end]
  V[SWO]
  W[smart ptr]
  X[std::ref]
  Y[string]
  Z[pair cmp]
  AA[b2s<br/>s2b]
	
	A-->B
	A-->C
	A-->D
	C-->E
	B-->F
	B-->G
	B-->K
	F-->I
	G-->J
	I-->M
	J-->L
	L-->H
	B-->N
	D-->P
	N-->O
	D-->Q
	Q-->R
	E-->S
	S-->T
  P-->U
  G-->V
  J-->W
  W-->X
  F-->Y
  V-->Z
  K-->AA
  
	style E fill:#9F9,stroke:#333,stroke-width:1px
	style L fill:#9FF,stroke:#333,stroke-width:1px
	style M fill:#FF9,stroke:#333,stroke-width:1px
	style P fill:#F99,stroke:#333,stroke-width:1px
	style V fill:#F00,stroke:#333,stroke-width:1px
	style AA fill:#FF0,stroke:#333,stroke-width:1px

容器&&迭代器&&算法

The concept of the STL is based on a separation of data and operations. The data is managed by container classes, and the operations are defined by configurable algorithms. Iterators are the glue between these two components

容器的部分特性

  1. If you insert elements, only lists, forward lists, and associative containers guarantee that iterators and references to elements remain valid
  2. Array 支持 tuple 接口,get<> / tuple_element<>::type / tuple_size<>::value
strict weak ordering

关联容器中需要比较大小的类型,比如 set 中的 value,map 中的 key,都需要满足 strict weak ordering。满足 SWO 的好处是只需要实现一个小于或者大与,系统就可以自动完成这些关系运算:\(\gt/\ge/\lt/\le/==/\neq\)

例如相等的定义为:

Two objects x and y are equivalent if both f(x, y) and f(y, x) are false

SWO 需要满足四个条件

  1. 反对称性(antisymmetric):f(x, y) implies !f(y, x),注意这里使用的是 x/y ,标示着二者的不同
  2. 传递性(transitive):f(x, y) and f(y, z) imply f(x, z)
  3. 反自反性(irreflexive):f(x, x) must be false
  4. 等号的传递性

数学上的 \(\le\) 不满足上面的要求,所以不能作为关联容器的比较运算符

pair cmp
p1.first<p2.first || (p1.first==p2.first && p1.second<p2.second);

假设 p1 first 比 p2 first 大,如果后面的比较不判断 first 的相等性,那么 p1.first > p2.first 的信息讲丢失

容器的复用:组合/私有继承

To add new behavior for containers, you should define a new class that internally uses STL classes or derives privately from them.

Seq容器
graph TB
	B[array]
	C[array T,N]
	D[fill]
	E[tuple<br/>interface]
	F[Seq]
	H[vec]
	I[double/2k]
	J[reserve]
	K[shrink]
	L[bool]
	M[flip]
	Q[deque]
	R[fast<br/>front/back]
	U[list]
	V[splice<br/>merge]
	X[forward]
	Y[no size]
	Z[begin/next]
	
	F-->B
	B-->C
	B-->D
	B-->E
	F-->H
	H-->I
	I-->J
	H-->K
	H-->L
	L-->M
	F-->Q
	Q-->R
	F-->U
	U-->V
	F-->X
	X-->Y
	Y-->Z
	
	style L fill:#FF9,stroke:#333,stroke-width:1px
  1. 为了减少内存碎片,部分实现中,vec 在第一次插入时直接申请一个 block 的内存空间,比如 2k
Ass 容器
graph TB
	A[Associate]
	B[set]
	C[op params]
	D[lower/up bound<br/>emplace_hint]
	E[value_type<br/>const]
	I[map]
	J[value_type]
	K[const Key, T]
	L[earse when it]
	
	A-->B
	B-->C
	B-->D
	B-->E
	A-->I
	I-->J
	J-->K
	I-->L
  1. 除模板上的比较方法,关联容器支持构造时提供比较方法参数
m.emplace(std::piecewise_construct, // pass tuple elements as arguments 
          std::make_tuple("hello"), // elements for the key 
          std::make_tuple(3.4,7.8)); // elements for the value
// 迭代过程中删除
for (auto pos = coll.begin(); pos != coll.end(); ) { 
  if (pos->second == value) { 
    pos = coll.erase(pos); // possible only since C++11 
  } else { 
    ++pos; 
  } 
}
Adapters
template <typename T, typename Container = deque<T>> class stack;
template <typename T, typename Container = deque<T>> class queue;

template <
			typename T, 
			typename Container = vector<T>, 
			typename Compare = less<typename Container::value_type>> 
class priority_queue; // 默认大顶堆
bitset

The class template bitset represents a fixed-size sequence of N bits. Bitsets can be manipulated by standard logic operators and converted to and from strings and integers.

template <size_t Bits> class bitset;

string s = bitset<42>(12345678).to_string(); 
cout << "12,345,678 with 42 bits: " << s << endl;

// transform binary representation into integral number 
cout << "\"1000101011\" as number: " << bitset<100>("1000101011").to_ullong() << endl;

// 12,345,678 with 42 bits: 000000000000000000101111000110000101001110 
// "1000101011" as number: 555

迭代器

Iterators are pure abstractions: Anything that behaves like an iterator is an iterator

迭代器按功能由简单到复杂可以分为三类,如下:

  1. 单向迭代器(Forward Iterator),unordered_set, unordered_multiset, unordered_map, and unordered_multimap are “at least” forward iterators
  2. 双向迭代器(Bidirectional iterator), list, set, multiset, map, and multimap are bidirectional iterators
  3. 随机迭代器(Random-access iterator),vector, deque, array, and iterators of strings are random access iterators
it != x.end() is better

迭代器可以没有大小运算符,但一般都有不等于运算符

Iterator Adapters
  1. back_insert,调用 push_back 实现数据插入

    copy (coll1.cbegin(), coll1.cend(), std::back_inserter(coll2));
    
  2. front_insert,调用 push_front 实现数据插入

  3. inserter(container, pos),调用 insert 实现数据插入

Stream Iterators
  1. istream_iterator<string>(cin) ,cin » str
  2. ostream_iterator<string>(cout,"\n"),xx « data
copy (istream_iterator<string>(cin), // start of source 
      istream_iterator<string>(), // end of source 
      back_inserter(coll)); // destination

unique_copy (coll.cbegin(), coll.cend(), // source 
             ostream_iterator<string>(cout,"\n")); // destination
关系与属性
graph LR
	A[itr]
	B[stream]
	C[forward]
	D[Bidirectional]
	E[rand]
	G[fd_list<br/>unorder]
	H[List/set/map<br/>ms/mm]
	I[arr/vec/dq<br/>str/c-arr]
	J[istream]
	K[ostream]
	

	
	A-->B
	B-->|it1=it2|C
	C-->|--it|D
	D-->|idx/+-/lt/gt|E
	C-->G
	D-->H
	E-->I
	B-->|++/acc/eq/type|J
	B-->|++/*it=val/acc/eq/type|K
	
	style B fill:#9F9,stroke:#333,stroke-width:1px
	style C fill:#9F9,stroke:#333,stroke-width:1px
	style D fill:#9F9,stroke:#333,stroke-width:1px
	style E fill:#9F9,stroke:#333,stroke-width:1px
  1. 使用原生指针实现的迭代器,其临时变量对象是不允许修改的,所以对于 vec 而言如此操作无效:++vec.begin()// maybe invalid。但对于 class 类型的迭代器,当前操作有效。为了通用,此种场景下可以使用 std::next()
迭代器辅助工具
graph TB
	A[itr aux funs]
	B[advance p,n<br/>distance]
	C[next/prev p/p,n]
	D[adapters]
	E[iter_swap]
	G[itr traits]
	J[traits]
	K[swap *it1,*it2]
	L[rbegin/rend]
	M[reverse]
	N[reverse_iterator]
	O[val changed]
	P[inserter]
	Q[back/front/insert]
	R[++ No-op]
	T[*it=val / it=val]
	U[push_back<br/>push_front<br/>insert]
	V[io/move itr]
	
	
	A-->B
	A-->C
	A-->D
	A-->E
	B-->J
	E-->K
	D-->M
	M-->L
	M-->N
	N-->O
	D-->P
	P-->Q
	Q-->R
	Q-->T
	T-->U
	A-->V
	A-->G
	
	
	style O fill:#F99,stroke:#333,stroke-width:1px
	style K fill:#F99,stroke:#333,stroke-width:1px
	style G fill:#F99,stroke:#333,stroke-width:1px

Functor

  1. A function object might be smarter and faster than function pointer
graph LR
	A[Functor]
	B[pre defs]
	C[plus/minus/div/modules...]
	D[binder&&adpter]
	E[bind/mem_fn]
	
	A-->B
	B-->C
	A-->D
	D-->E

算法

  1. 只有 for_each 返回 op 对象,其他算法均不返回
  2. All algorithms process one or more ranges of elements
  3. Algorithms work in overwrite mode rather than in insert mode. Thus, the caller must ensure that destination ranges have enough elements
graph TB
	A[Algs]
	B[tips]
	C[OP]
	D[Stateless]
	E[suffix if/copy]
	F[classes]
	G[nomodify]
	H[modify]
	I[all_off/is_heap/max_element]
	J[copy_if/merge/fill]
	K[remove/unique/partation]
	
	A-->B
	B-->C
	C-->D
	B-->E
	A-->F
	F-->G
	F-->H
	G-->I
	H-->J
	H-->K
	
	style D fill:#F99,stroke:#333,stroke-width:1px

Stateless OP

A predicate should always be stateless

下面是 remove_if 的实现方式,注意 op 是以传值的形式传输的,op 中的状态并不能传递。标准库对代码的实现没有严格规范,所以 op 尽量保证无状态

template <typename ForwIter, typename Predicate> 
ForwIter std::remove_if(ForwIter beg, ForwIter end, Predicate op) { 
  beg = find_if(beg, end, op); // 注意这里第一次以传值的形式使用 op,状态不会传递
  // while (beg != end && !op(*beg)) { ++beg; }  // 如果标准库的实现类似于此,就没有问题
  
  if (beg == end) { 
    return beg; 
  } else { 
    ForwIter next = beg; 
    return remove_copy_if(++next, end, beg, op); // 注意这里第二次使用传值的形式使用 op 
  } 
}

部分算法函数

  1. count / min_element / minmax_element
  2. find_first_of / find_end / adjacent_find / is_permutation ,at worst quadratic
  3. mismatch,寻找两数组间第一个不同的地方,lexicographical_compare
  4. is_sorted / is_heap / is_partationed / partation_point
  5. If the range is empty, all_of() and none_of() return true, whereas any_of() returns false.
  6. binary_search (非随机迭代器退化为 普通查找)/ lower_bound
  7. copy_backward / move_backward / swap_range / replace_copy / merge / implace_merge
  8. reverse / reverse_copy / rotate / rotate_copy / partation / stable_partation / partation_copy
  9. transform / fill / fill_n / generate / generate_n / iota
  10. remove / unique / remove_copy / unique_copy , cannot change the number of elements
  11. prev_permutation / next_permutation . Both algorithms return false if the elements got the “normal” (lexicographical) order
  12. shuffle / random_shuffle ,For shuffle(), you should not pass an engine just temporarily created. 很多随机数生成函数使用了全局变量,所以随机性比较差。连续多次使用 shuffle 时最好创建一个局部随机对象,避免每次都创建新的随机数生成对象
  13. sort(平均 nlogn )/ stable_sort (保证 nlogn )/ partial_sort / nth_element
  14. make_heap / push_heap / sort_heap
  15. set_union / set_difference / set_symmetric_difference / set_intersection
  16. accumulate / inner_product
  17. partial_sum , a1, a1 + a2, a1 + a2 + a3
  18. adjacent_difference, a1, a2 - a1, a3 - a2, a4 - a3

std::string

graph TB
	A[string]
	B[member]
	C[npos]
	D[means all data]
	E[helper]
	F[getline]
	G[first_not_of]
	H[template]
	I[wstring<br/>u16string<br/>u32string]
	J[binary<br/>safe]
	K[attrs]
	L[num2str]
	M[just str/wstr]
	N[skip/last/base/thr]
	O[rnd itr]
	P[use algs]
	
	A-->B
	B-->C
	C-->D
	A-->E
	E-->F
	B-->G
	H-->I
	A-->H
	A-->K
	K-->J
	E-->L
	L-->M
	L-->N
	K-->O
	O-->P
	
	style N fill:#F99,stroke:#333,stroke-width:1px
	style J fill:#9F9,stroke:#333,stroke-width:1px

std::string 由模版实现,所以很方便进行扩展,C++11 后标准库提供了如下类型:

typedef basic_string<wchar_t> wstring; 
typedef basic_string<char16_t> u16string; 
typedef basic_string<char32_t> u32string;

string 不支持字符初始化,但支持字符初始化列表初始化:

std::string s(’x’); // ERROR 
std::string s(1,’x’); // OK, creates a string that has one character ’x’
std::string s({’x’}); // OK, ditto (since C++11)

常用函数

getline(std::cin,s,’:’) // get token separated by : 

stoi(str,idxRet=nullptr, base=10);
std::stoi (" 42 is the truth", &idx);
std::stoi (" 42", nullptr, 16);

Another tools

graph TB
	A[tools]
	B[regex]
	C[IO stream]
	D[i18n]
	E[local]
	F[Num]
	K[ECMA]
	L[cmatch<br/>wsmatch]
	M[itr]
	N[part<br/>thread safe]
	O[store]
	P[multibyte]
	Q[wide char]
	R[utf8 1-4B]
	S[utf16 2/4B]
	T[char<br/>char32_t]
	U[utf32]
	V[BOM]
	W[isupper<br/>toupper<br/>print]
	X[random]
	Y[Engine]
	Z[careful<br/>tmp obj]
	AA[Distrs]
	AB[liner/Guass]
	AC[dre]
	AD[int/float]
	AE[full/half]
	
	
	A-->B
	A-->C
	A-->D
	B-->K
	K-->L
	B-->M
	C-->N
	D-->O
	O-->P
	O-->Q
	P-->R
	P-->S
	Q-->T
	Q-->U
	U-->V
	S-->V
	D-->E
	E-->W
	A-->F
	F-->X
	X-->Y
	Y-->Z
	X-->AA
	AA-->AB
	Y-->AC
	AB-->AD
	AD-->AE
	
	style Z fill:#F99,stroke:#333,stroke-width:1px
	style AC fill:#9F9,stroke:#333,stroke-width:1px
	style AE fill:#99F,stroke:#333,stroke-width:1px

regex

match interface:

i18n

  1. BOM,byte order mark

encoding

C++ provides different character types to deal with these character sets:

  1. char can be used for all character sets up to 8 bits, such as US-ASCII, ISO-Latin-1, and ISOLatin-9. In addition, it can be used for octets of UTF-8
  2. char16_t (provided since C++11) can be used for UCS-2 and as code unit for UTF-16
  3. char32_t(provided since C++11) can be used for UCS-4/UTF-32
  4. wchar_t is the type for the values of the largest extended character set among all supported locales. Thus, it is usually equivalent to char16_t or char32_t

local

Changing the locale influences the results of character classification and manipulation functions, such as isupper() and toupper(), and the I/O functions, such as printf().

Random

Engines

C++ 提供了多种随机数生成引擎,在初始状态相同的情况下,这些对象生产的随机数序列是相同的,不同随机数生成引擎其安全性与性能均不相同,需要按需使用

careful with tmp

因为随机数引擎生成的数据依赖于初始状态,所以尽量不推荐使用临时变量形式的引擎。下面两行 shuffle 其结果是一样的,因为随机数序列是相同的(临时的 dre,其初始状态相同)。当前概念适用其他引擎

std::ostringstream engineState; 
engineState << dre;

std::shuffle(v.begin(),v.end(), // range 
             std::default_random_engine()); // random-number generator ...

std::shuffle(v.begin(),v.end(), // range 
             std::default_random_engine()); // random-number generator

对随机性要求不高的场景,可以为 dre 提供一个随机数种子,以实现不同调用之间的随机性

std::shuffle(v.begin(),v.end(), // range 
             std::default_random_engine(x)); // x = time + exe_count
std::default_random_engine

std::default_random_engine 的实现依赖不同编译器,这个随机数生成器的实现方法标准库没做要求,适用于一般场景,性能和随机性不会很差

rand()%n is bad

The technique to compute random numbers by using rand()%n in practice fails for two reasons:

  1. Many pseudo-random-number generator implementations give remainders that aren’t very random, when the quotients passed as n are small integers. For example, it is not uncommon for successive results of rand() to be alternately even and odd. In that case, if n is 2, successive results of rand()%n will alternate between 0 and 1.

  2. On the other hand, if the value of n is large, and the generated maximum value is not evenly divisible by n, some remainders will appear more often than others. For example, if the maximum is 32767 and n is 2000, 17 generated values (500, 2500, …, 30500, 32500) would map to 500, while only 16 generated values (1500, 3500, …, 31500) would map to 1500. And this gets worse the larger n is.

valarrays

Complex Numbers

complex / polar

Concurrency

Allocators