C++11 新标准(五)

来源:互联网 发布:securecrt mac 破解 编辑:程序博客网 时间:2024/06/05 16:46

1.散列表(哈希表)unordered_map

(1)哈希表是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度,这个映射函数叫做散列函数。
哈希表的一个重要问题就是如何解决映射冲突的问题。常用的有两种:开放地址法和链地址法
(2)与map的区别:
STL中,map对应的数据结构是红黑树。红黑树是一种近似于平衡的二叉查找树,里面的数据是有序的。在红黑树上做查找操作的时间复杂度为 O(logN)。而unordered_map对应 哈希表,哈希表的特点就是查找效率高,时间复杂度为常数级别 O(1), 而额外空间复杂度则要高出许多。所以对于需要高效率查询的情况,使用unordered_map容器。而如果对内存大小比较敏感或者数据存储要求有序的话,则可以用map容器
(3)unordered_map的用法和map大同小异,一个简单示例:
#include <iostream>#include <unordered_map>#include <string>int main(int argc, char **argv) {    std::unordered_map<int, std::string> map;    map.insert(std::make_pair(1, "Scala"));    map.insert(std::make_pair(2, "Haskell"));    map.insert(std::make_pair(3, "C++"));    map.insert(std::make_pair(6, "Java"));    map.insert(std::make_pair(14, "Erlang"));   for(auto iter:map){std::cout << iter.first << ' ' << iter.second << std::endl;}    return 0;}
(4)要使用哈希表,必须要有对应的计算散列值的算法以及判断两个值(或对象)是否相等的方法。
因此如果想在unordered_map中使用自定义的类,则必须为此类提供一个哈希函数和一个判断对象是否相等的函数
(5)其他散列表类型:std::unordered_set,std::unordered_mulitmap,std::unordered_mulitset,并引入头文件<unordered_map>和<unordered_set>

2.weak_ptr

(1)std::weak_ptr 是一种智能指针,它对被 std::shared_ptr 管理的对象存在非拥有性(“弱”)引用。
此模板类描述一个对象,指向由一个或多个管理的资源shared_ptr 类对象。 指向某个资源的 weak_ptr 对象不会影响资源的引用计数。 因此,当最后一个管理该资源 shared_ptr 的对象被销毁时,则即使存在指向该资源的 weak_ptr 对象,该资源也将被释放。 这对于避免数据结构中的循环至关重要
调用已过期的 weak_ptr 对象上的 lock 将创建一个空 shared_ptr 对象。
空 weak_ptr 对象不会指向任何资源,而且没有控制块。 其成员函数 lock 将返回一个空 shared_ptr 对象。
(2)特点:
只有当对象存在的时候,你才需要对其进行访问
并且它可能被其他人删除释放
并且在最后一次使用之后调用其析构函数(通常用于释放那些不具名的内存(anon-memory)资源
(3)比较
//shared_ptr版 #include <iostream>#include <memory>using namespace std;shared_ptr<int> gw;void f(){    if (auto spt = gw ){ std::cout << *spt << "\n";    }    else {        std::cout << "gw is expired\n";    }} int main(){    {        auto sp = std::make_shared<int>(42);gw = sp; f();    } //脱离{},sp销毁,但gw仍存在看,gw指向的空间不销毁    f();}/*输出结果为:42 42*/ 

//weak_ptr版#include <iostream>#include <memory> std::weak_ptr<int> gw; void f(){    if (auto spt = gw.lock()) { // 使用之前必须复制到 shared_ptrstd::cout << *spt << "\n";    }    else {        std::cout << "gw is expired\n";    }} int main(){    {        auto sp = std::make_shared<int>(42);gw = sp; f();    }    //脱离{},sp销毁,gw指向的空间跟着销毁     f();}/*输出结果为:42gw is expired */

3.可扩展的随机数功能

(1)C 标准库允许使用rand函数来生成伪随机数。不过其算法则取决于各程序库开发者。 这个函数产生一定范围内的一个均匀随机整数。如果需要其他随机分布或者其他范围的随机数,就需要根据rand函数产生的随机数进行再加工,不过这时,就容易引入非随机性了。
C++11新标准中引入了一个新的随机数库,相关功能定义在random头文件中,通过多个互相协作的类,可以生成任意范围内、服从多种随机分布的随机数。
(2)C++11 的随机数功能分为两部分: 第一,一个乱数生成引擎,其中包含该生成引擎的状态,用来产生乱数。第二,一个分布,这可以用来决定产生乱数的范围,也可以决定以何种分布方式产生乱数。乱数生成对象即是由乱数生成引擎和分布所构成
不同于C标准库的 rand; 针对产生乱数的机制,C++11 将会提供三种随机数生成引擎,每一种算法都有其强项和弱项:

样板类整数/浮点数质量速度状态数linear_congruential 整数低中等1subtract_with_carry两者皆可中等快25mersenne_twister整数佳快624
(3)C++11 将会提供一些标准分布: uniform_int_distribution (离散型均匀分布),bernoulli_distribution (伯努利分布),geometric_distribution (几何分布), poisson_distribution (卜瓦松分布),binomial_distribution (二项分布),uniform_real_distribution (离散型均匀分布), exponential_distribution (指数分布),normal_distribution (正态分布) 和 gamma_distribution (伽玛分布)。
#include <iostream>#include <random>int main(){// 以离散型均匀分布产生随机数,范围0-99     std::uniform_int_distribution<int> distribution(0, 99);         // 建立随机数生成引擎std::mt19937 engine;for(int i = 0;i < 100;i++){//产生随机数 std::cout << distribution(engine) << std::endl;}return 0;}

随机数引擎接受一个整形参数当作种子,不提供的话,会使用默认值. 推荐使用random_device来产生一个随机数当作种子.std::random_device rd;std::mt19937 mt(rd());

还可以使用bind将随机数生成引擎和分布组合成一个随机数生成器#include <functional>auto generator = std::bind(distribution, engine);std::cout << generator()<< std::endl; //产生随机数

4.包装引用

(1) 我们可以通过实体化样板类 reference_wrapper 得到一个包装引用 (wrapper reference)。包装引用类似于一般的引用。对于任意对象,我们可以通过模板类 ref 得到一个包装引用 (至于 constant reference 则可通过 cref 得到)
(2)当样板函数需要形参的引用而非其拷贝,这时包装引用就能派上用场:
#include <iostream>#include <functional>void f(int &r){r++;std::cout << "In function f: " << r << std::endl;}template <typename  F,class P>void g(F f,P p){f(p);}int main(){using namespace std;int i = 0;g(f,i);cout << "In function main: " << i << endl;g(f,ref(i));cout << "In function main: " << i << endl;    return 0;}/*输出结果为:In function f: 1In function main: 0In function f: 1In function main: 1 */
这项功能将加入头文件 <utility>

4.元编程

元编程的定义是可以修改自身或其他代码的代码,当然,C++不是动态语言,这个修改可以在编译或执行的时期

5.计算函数对象返回类型

在编译期决定一个样板仿函数的返回值类别并不容易,特别是当返回值依赖于函数的实参时。举例来说:
struct Clear{int operator()(int); //当仿函数的返回值总是和Clear一致时,容易推断;double operator()(double);};template <typename Obj>class Calculus{public:template<typename Arg>Arg operator()(Arg& a){return member(a);}private:Obj member;};//但是当仿函数的返回值和Clear不一致时;struct Clear{int operator()(double); double operator()(int);};
C++11支持一个模板函数std::result_of,它使用了decltype并支持函数对象
std::result_of<T>::type 即是返回类型,比如:
#include <iostream>#include <functional>class Clear{public:int operator()(double a){return i;} double operator()(int a){return d;}private:int i = 0;double d = 1.1;};template <typename T>class Calculus{public:template<typename Arg>typename std::result_of<T(Arg)>::type operator()(Arg a){return member(a);}private:T member;};int main(){Calculus<Clear> i;std::cout << i(0) << " " << i(1.1) << std::endl;}


0 0