关闭

C++11在时空性能方面的改进

发表于:2015-9-08 09:31

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:大CC    来源:51Testing软件测试网采编

  这篇我们聊聊C++11在时间和空间上的改进点;
  主要包括以下方面:
  新增的高效容器:array、forward_list以及unordered containers;
  以及常量表达式、静态断言和move语义;
  大小固定容器 array
  std::array是一个支持随机访问且大小(size)固定的容器,它是c++11中新增的容器。它有如下特点:
  不预留多余空间,只分配必须空间(译注:size() == capacity())。
  可以使用初始化表(initializer list)的方式进行初始化。
  保存了自己的size信息。
  不支持隐式指针类型转换。
  可以认为它是一个很不错的内建数组类型。示例:
  array<int,6> a = { 1, 2, 3 };
  a[3]=4;
  int x = a[5];    // array的默认数据元素为0,所以x的值变成0
  int* p1 = a; // 错误: std::array不能隐式地转换为指针
  int* p2 = a.data(); // 正确,data()得到指向第一个元素的指针
  可以认为array是一个紧缩版的vector,它比vector高效(没有自动空间分配),但缺少了push_back这样的神器,使得它的使用场景一般是用来替换c++内建的数组类型,而不是vector;
  前向列表 forward_list
  c++11新增的容器:前向列表 forward_list
  前向列表是一个能够在任意位置快速插入和删除的容器(列表都这特性,前向列表当然也具有这特性),但不支持快速随机存取。
  它是用单向链表实现的,相比较于它的C实现而言没有什么额外开销。相较于std::list而言,此容器耗费的空间更少,因为它是单向的,不是双向的。
  std::forward_list<int> mylist (3,5);   // 3 ints with value 5
  for (int& x : mylist ) std::cout << " " << x;
  哈希表[无序容器] unordered containers
  hash容器在很多之前的编译器中就包含进来了;比如gcc 较早的版本中,它存在于tr1命名空间中;
  以unordered_map为例,unordered_map基于散列表实现,元素之间无序存储;
  而map基于红黑树实现,元素之间有序(通过operator< 进行比较);
  hash版本的查找时间复杂度为O(1),在数据量很大时,比红黑树的版本效率高很多;
  对比在C++11中和之前使用上的区别:
  // c++0x中:
  #include <tr1/unordered_map>
  std::tr1:: unordered_map< char,int >  map1;
  map1.insert(std::pair<char,int>('a',100) );
  // C++11中:
  #include <unordered_map>
  std::unordered_map< char,int >  map1;
  map1.insert(std::pair<char,int>('a',100) );
  常量表达式 constexpr
  编译期计算(Compile-time evaluation):常量表达式
  在程序中,有些计算是与运行时无关的;每次执行都是相同的结果;
  常量表达式允许让这些计算发生在编译时,而不是在运行时;
  这样利用编译时的计算能力,将显著提升程序执行时的效果;
  eg:对函数申明为constexpr
  constexpr int multiply (int x, int y)
  {
  return x * y;
  }
  // 将在编译时计算
  const int val = multiply( 10, 10 );
  cin >> x;
  // 由于输入参数x只有在运行时确定,所以以下这个不会在编译时计算,但执行没问题
  const int val2 = mutliply(x,x);
  静态断言 static_assert
  static_assert提供一个编译时的断言检查。如果断言为真,什么也不会发生。如果断言为假,编译器会打印一个特殊的错误信息。由于是在编译期间执行的,所以它不会影响运行时的性能;
  expression在编译期进行求值,当结果为false(即:断言失败)时,将string作为错误消息输出。例如:
  static_assert(sizeof(long) >= 8,
  “64-bit code generation required for this library.”);
  struct S { X m1; Y m2; };
  static_assert(sizeof(S)==sizeof(X)+sizeof(Y), ”unexpected padding in S”);
  static_assert在判断代码的编译环境方面十分有用,比如判断当前编译环境是否64位。但需要注意的是,由于static_assert在编译期进行求值,它不能对那些依赖于运行期计算的值的进行检验。例如:
  int f(int* p, int n)
  {
  //错误:表达式“p == 0”不是一个常量表达式
  static_assert(p == 0,
  “p is not null”);
  }
  正确的做法是在运行期进行判断,假如条件不成立则抛出异常;
21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号