C++ standard
参考资料:
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
- u8 defines a UTF-8 encoding
- u defines a string literal with characters of type
char16_t
- U defines a string literal with characters of type
char32_t
- 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
- unary 示例:
is_void<T>
/is_signed<T>
等等 - Relation 示例:
is_same<T,D>
/is_base_of<T,D >
等等 - 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
- pair 可以使用 tuple 的接口
- pair 有三种构造函数,前两种常规构造,第三种利用了
std::piecewise_construct
以实现与前两种构造的区分。第三种构造函数用于 first/second 构造需要多个参数的场景 - 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
智能指针
- 优先使用
make_shared/make_unique
。可以减少内存分配的次数并减少出错的几率 - 智能指针本身不是线程安全的,比如 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 有两个功能:
- 解决 sharedptr 的循环引用问题
- 共享但又不想持有,
weak_ptr
和shared_ptr
有着相同类型的控制块,所以二者之间可以相互转换。也因为这个原因,weak_ptr
的构造函数只接受shared_ptr
你不能直接使用 weak_ptr
,需要先将其转换为 shared_ptr
- sharedptr 支持使用 weakptr 构造,如果 weakptr 无效,则抛异常(
bad_weak_ptr
) - 调用 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
容器的部分特性
- If you insert elements, only lists, forward lists, and associative containers guarantee that iterators and references to elements remain valid
- 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 需要满足四个条件:
- 反对称性(antisymmetric):
f(x, y)
implies!f(y, x)
,注意这里使用的是 x/y ,标示着二者的不同 - 传递性(transitive):
f(x, y)
andf(y, z)
implyf(x, z)
- 反自反性(irreflexive):
f(x, x)
must befalse
- 等号的传递性
数学上的 \(\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
- 为了减少内存碎片,部分实现中,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
- 除模板上的比较方法,关联容器支持构造时提供比较方法参数
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
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
迭代器按功能由简单到复杂可以分为三类,如下:
- 单向迭代器(Forward Iterator),unordered_set, unordered_multiset, unordered_map, and unordered_multimap are “at least” forward iterators
- 双向迭代器(Bidirectional iterator), list, set, multiset, map, and multimap are bidirectional iterators
- 随机迭代器(Random-access iterator),vector, deque, array, and iterators of strings are random access iterators
it != x.end()
is better
迭代器可以没有大小运算符,但一般都有不等于运算符
Iterator Adapters
-
back_insert
,调用push_back
实现数据插入copy (coll1.cbegin(), coll1.cend(), std::back_inserter(coll2));
-
front_insert
,调用push_front
实现数据插入 -
inserter(container, pos),调用 insert 实现数据插入
Stream Iterators
istream_iterator<string>(cin)
,cin » strostream_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
- 使用原生指针实现的迭代器,其临时变量对象是不允许修改的,所以对于 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
- 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
算法
- 只有
for_each
返回 op 对象,其他算法均不返回 - All algorithms process one or more ranges of elements
- 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
}
}
部分算法函数
- count /
min_element
/minmax_element
find_first_of
/find_end
/adjacent_find
/is_permutation
,at worst quadratic- mismatch,寻找两数组间第一个不同的地方,
lexicographical_compare
is_sorted
/is_heap
/is_partationed
/partation_point
- If the range is empty,
all_of()
andnone_of()
return true, whereasany_of()
returns false. binary_search
(非随机迭代器退化为 普通查找)/lower_bound
copy_backward
/move_backward
/swap_range
/replace_copy
/merge
/implace_merge
reverse
/reverse_copy
/ rotate /rotate_copy
/ partation /stable_partation
/partation_copy
- transform / fill /
fill_n
/ generate /generate_n
/iota
remove
/unique
/remove_copy
/unique_copy
, cannot change the number of elementsprev_permutation
/next_permutation
. Both algorithms return false if the elements got the “normal” (lexicographical) ordershuffle
/random_shuffle
,For shuffle(), you should not pass an engine just temporarily created. 很多随机数生成函数使用了全局变量,所以随机性比较差。连续多次使用 shuffle 时最好创建一个局部随机对象,避免每次都创建新的随机数生成对象sort
(平均 nlogn )/stable_sort
(保证 nlogn )/partial_sort
/nth_element
make_heap
/push_heap
/sort_heap
set_union
/set_difference
/set_symmetric_difference
/set_intersection
accumulate
/inner_product
partial_sum
, a1, a1 + a2, a1 + a2 + a3adjacent_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
- BOM,byte order mark
encoding
C++ provides different character types to deal with these character sets:
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-8char16_t
(provided since C++11) can be used for UCS-2 and as code unit for UTF-16char32_t
(provided since C++11) can be used for UCS-4/UTF-32wchar_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:
-
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.
-
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
略