在c++11之前,实现一个通用的泛型单例模式时,会遇到一个问题:这个泛型单例要能够创建所有的类型对象,但是这些类型的构造函数形参可能不尽相同,参数个数和参数类型可能都不同,这导致我们不容易做一个所有类型都通用的单例。现在c+11帮助我们解决了这个问题,解决这个问题靠的是c++11的可变模板参数。C++11版本的通用单例模式的实现,没有了重复的模板定义,支持任意个数参数的类型创建,不用担心模板函数定义得不够,还支持完美转发,无论是左值还是右值都能转发到正确的构造函数中,通过右值引用的移动语义还能进一步提高性能,简洁而优雅。
C++11中引入了右值引用和移动语义,可以避免无谓的复制,提高程序性能。相应的,C++11的容器还增加了一些右值版本的插入函数。
通过这些函数我们可以避免不必要的拷贝,提高程序性能。move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝。如图所示是深拷贝和move的区别。
这种移动语义是很有用的,比如我们一个对象中有一些指针资源或者动态数组,在对象的赋值或者拷贝时就不需要拷贝这些资源了。定义拷贝构造函数和赋值函数的更有效的方法是直接交换a和临时对象中的资源指针,然后让临时对象的析构函数去销毁a原来拥有的资源。 如果不用std::move,拷贝的代价很大,性能较低。使用move几乎没有任何代价,只是转换了资源的所有权。如果一个对象内部有较大的对内存或者动态数组时,很有必要写move语义的拷贝构造函数和赋值函数,避免无谓的深拷贝,以提高性能。
右值引用类型是独立于值的,一个右值引用参数作为函数的形参,在函数内部再转发该参数的时候它已经变成一个左值了,并不是它原来的类型了。因此,我们需要一种方法能按照参数原来的类型转发到另一个函数,这种转发被称为完美转发。所谓完美转发(perfect forwarding),是指在函数模板中,完全依照模板的参数的类型,将参数传递给函数模板中调用的另外一个函数。c++11中提供了这样的一个函数std::forward,它是为转发而生的,它会按照参数本来的类型来转发出去,不管参数类型是T&&这种未定的引用类型还是明确的左值引用或者右值引用。
C++11增加了无序容器unordered_map/unordered_multimap和
unordered_set/unordered_multiset,由于这些容器中的元素是不排序的,因此,比有序容器map/multimap和set/multiset效率更高。
无序集合(Unordered Set)容器是一个存储唯一(Unique,即无重复)元素的关联容器(Associative container),容器中的元素无特别的次序关系。该容器允许基于值地快速元素检索。
在一个 unordered_set 容器中,元素的值同时可以用来标志对应的元素(即值是自身的主键),每个值必须是唯一的。主键是不可修改的,因此在 unordered_set 中的元素不能被逐个修改(所有元素保持恒定),但是可以删除某个元素或插入新的元素。
在 unordered_set 内部,元素不会按任何顺序排序,而是通过元素值的 hash 值将元素分组放置到各个槽(Bucket,也可译成“桶”)中,这样就能通过元素值快速地访问各个对应的元素(平均耗时为一个常量,即时间复杂度为 O(1))。
除了排序(std::sort 等)、堆操作(std::make_heap、std::sort_heap 等)、第n个元素(std::nth_element),适用于 std::vector 的例子基本上都适用于 std::unordered_set,与unordered_set相关的算法可参考vector相关的算法。
Array—>新的标准库std::array
C++11中引入了array容器,array是序列容器的一种。array很类似于一般的数组,例如,array在栈上分配连续的内存来储存元素,并且array的大小是不可以改变的,这也就是说,可以修改array中元素的值,但不能向array中插入和删除元素。
array具有序列容器的特点,同时又具有一般数组的特点,实际上,在程序中需要使用数组的地方,都可以使用array来代替,使用array更为安全,除了具有一般数组的灵活性,还具有与一般数组相近的性能优势。
Array内部只存储所包含的数据,哪怕是大小也只不过是个模板参数。和普通使用‘[]’语法申明的数组相比,只不过显得更加高效(操作高效),因为这个类添加了一系列的全局成员函数用来操作这些元素。
C++11的一些特性可以使程序更简洁易读,也更现代。通过这些新特性,可以更方便和高效地撰写代码,并提高开发效率。
在C++98/03中我们只能对普通数组和POD(plain old data,简单来说就是可以用memcpy复制的对象)类型可以使用列表初始化,如下:
数组的初始化列表: int arr[3] = {1,2,3}
在C++11中初始化列表被适用性被放大,可以作用于任何类型对象的初始化。
让人惊奇的是在C++11中可以使用列表初始化方法对堆中分配的内存的数组进行初始化,而在C++98/03中是不能这样做的。
C++11中增加了std:fuction和std::bind,不仅让我们使用标准库函数时变得更加方便,而且还能方便地实现延迟求值。
标准库函数bind()和function()定义于头文件中(该头文件还包括许多其他函数对象),用于处理函数及函数参数。类模版 std::function 是一种通用、多态的函数封装。
Function新的标准库std::function
std::function 是可调用对象的包装器。它是一个模板类,它的实例可以对任何可以调用的目标进行存储、复制、和调用操作,这些目标包括函数、lambda 表达式、绑定表达式、以及其它函数对象等。通过指定它的模板参数,可以用统一的方式处理函数、函数对象、函数指针,并允许保存和延迟执行它们。
std::bind用来将可调用对象与其参数一起进行绑定。绑定后的结果可以使用std::function进行保存,并延迟调用到任何我们需要的时候。
主要有两大作用:
1) 将可调用对象与其参数一起绑定成一个仿函数。
2) 将多元(参数个数为n,n>1)可调用对象转成一元或者(n-1)元可调用对象,即只绑定部分参数。
lambda表达式是C++11最重要也最常用的一个特性之一。lambda来源于函数式编程的概念,也是现代编程语言的一个特点。
lambda表达式有如下优点:
1).声明式编程风格:就地匿名定义目标函数或函数对象,不需要额外写一个命名函数或者函数对象。以更直接的方式去写程序,好的可读性和可维护性。
2).简洁:不需要额外再写一个函数或者函数对象,避免了代码膨胀和功能分散,让开发者更加集中精力在手边的问题,同时也获取了更高的生产率。
3).在需要的时间和地点实现功能闭包,使程序更灵活。
tuple是一个固定大小的不同类型值的集合,是泛化的std::pair。和c#中的tuple类似,但是比c#中的tuple强大得多。我们也可以把他当做一个通用的结构体来用,不需要创建结构体又获取结构体的特征,在某些情况下可以取代结构体使程序更简洁,直观。
tuple<const char*, int>tp = make_tuple(sendPack,nSendSize);
\\等价于
struct A
{
char* p;
int len;
};
C++ 定义了许多”范围 (range) “的概念。范围表现有如受控制的列表 (list),持有容器中的两点。有序容器是范围概念的超集 (superset),有序容器中的两个迭代器 (iterator) 也能定义一个范围。这些概念以及操作的算法,将被并入 C++11 标准程序库。为了在遍历容器时支持”for_each”用法,C++11扩展了for语句的语法。用这个新的写法,可以遍历C类型的数组、初始化列表以及任何重载了非成员的begin()和end()函数的类型。如果你只是想对集合或数组的每个元素做一些操作,而不关心下标、迭代器位置或者元素个数,那么这种foreach的for循环将会非常有用。不过 C++11 将会以语言层次的支持来提供范围概念的效用。
简单用法如下:
int my_array[5] = {1, 2, 3, 4, 5};
for (int &x : my_array)
{
x *= 2;
}
上面 for 述句的第一部份定义被用来做范围迭代的参数,就像被声明在一般 for 循环的参数一样,其作用域仅只于循环的范围。而在”:”之后的第二区块,代表将被迭代的范围。
Type Traits就是“类型的特征”的意思。在C++编程中,使用Type Traits来判断类型的特性,并根据这些类型信息选择应有的操作。通过type_traits可以实现在编译期计算、查询、判断、转换和选择,增强了泛型编程的能力,也增强了我们程序的弹性,使得我们在编译期就能做到优化改进甚至排错,能进一步提高代码质量。type_traits在一定程度上可以消除冗长的swich-case或者if-else的语句,降低程序的圈复杂度,提高代码可维护性。
C++11中有unique_ptr、shared_ptr与weak_ptr等智能指针,可以对动态资源进行管理
unique_ptr“唯一”拥有其所指对象,同一时刻只能有一个unique_ptr指向给定对象(通过禁止拷贝语义、只有移动语义来实现)。
unique_ptr指针本身的生命周期:从unique_ptr指针创建时开始,直到离开作用域。离开作用域时,若其指向对象,则将其所指对象销毁(默认使用delete操作符,用户可指定其他操作)。unique_ptr指针与其所指对象的关系:在智能指针生命周期内,可以改变智能指针所指对象,如创建智能指针时通过构造函数指定、通过reset方法重新指定、通过release方法释放所有权、通过移动语义转移所有权。
unique_ptr的使用场景:
(1)动态资源的异常安全保证(利用其RAII特性):
(2) 返回函数内创建的动态资源
(3) 可放在容器中(弥补了auto_ptr不能作为容器元素的缺点)管理动态数组,因为unique_ptr有unique_ptr<>重载版本,销毁动态对象时调用delete[]
auto_ptr 对象将会绑定一个指定类型的指针,并且负责该指针资源的释放。一般用法是auto_ptrpStruct(new MyStruct)定义了一个智能指针对象 pStruct, 该对象用于管理一个类型为 MyStruct 的指针。在auto_ptr类里,有一个指针成员变量,由该成员变量保存指针的地址。
shared_ptr 使用引用计数的方式来实现对指针资源的管理。同一个指针资源,可以被多个 shared_ptr 对象所拥有,直到最后一个 shared_ptr 对象析构时才释放所管理的对象资源。可以说,shared_ptr 是最智能的智能指针,因为其特点最接近原始的指针。不仅能够自由的赋值和拷贝,而且可以安全的用在标准容器中。shared_ptr 和 auto_ptr 一样,也是重载了-> 和 * 操作符,使用 get() 函数可以得到原始的指针,auto_ptr 提供了隐式的bool类型转换,可以直接用于判断auto_ptr对象是否绑定了指针资源。 use_cout() 用于返回当前资源的引用计数。
分子:描述精确的有理数分数。绝对值必须在 intmax_t 类型可描述的范围内。intmax_t 是最宽的带符号整数类型。
分母:绝对值必须在 intmax_t 类型可描述的范围内,且不能为 0。
intmax_t 是最宽的带符号整数类型。
提供了一个非确定性随机数生成设备。并把随机数抽象成随机数引擎和分布两部分.引擎用来产生随机数,分布产生特定分布的随机数(比如平均分布,正太分布等).
C++0x中引入了static_assert这个关键字,用来做编译期间的断言,因此叫做静态断言。
其语法很简单:static_assert(常量表达式,提示字符串)。
如果第一个参数常量表达式的值为真(true或者非零值),那么static_assert不做任何事情,就像它不存在一样,否则会产生一条编译错误,错误位置就是该static_assert语句所在行,错误提示就是第二个参数提示字符串。
enable_if 的主要作用就是当某个 condition 成立时,enable_if可以提供某种类型。enable_if在标准库中通过结构体模板实现的。
但是当 condition 不满足的时候,enable_if<>::type 就是未定义的,当用到模板相关的场景时,只会 instantiate fail,并不会编译错误
mem_fn里面的mem就是指类的成员member, 而fn就是指function, 加在一起就是说member function,即mem_fn是用来适配类的成员函数的,将成员函数(Member function)转化成函数对象(指针(Pointer)版)。
用从参数推导出的类型确定的模板参数,创建一个 reference_wrapper 对象。即返回std::reference_wrapper(类似于指针)。
交换两个对象的值。此处的对象不仅是变量还可以是数组,或任意类型的对象。
正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。主要的算法为regex_search, regex_match, regex_replace.
1、regex_match 判断一个正则表达式(参数 e)是否匹配整个字符序列 str. 它主要用于验证文本。注意,这个正则表达式必须匹配被分析串的全部,否则函数返回 false.如果整个序列被成功匹配,regex_match 返回 True.
2、regex_search 类似于 regex_match, 但它不要求整个字符序列完全匹配。
3、regex_replace 在整个字符序列中查找正则表达式e的所有匹配。这个算法每次成功匹配后,就根据参数fmt对匹配字符串进行格式化。缺省情况下,不匹配的文本不会被修改,即文本会被输出但没有改变。