一段代码展示 C++11/14/17 的语言特性

Title: Example Code Snippet for C++11/14/17 New Features
本文地址:http://blog.csdn.net/madongchunqiu/article/details/93721118

好多年没使用c++了,不经意间都快到C++20了。期间虽然学习了一些C++11/14/17的新功能,但是到底没有实践,忘起来也特别的快。即使买了 Effective Modern C++ 的影印版,也一直都没看。昨天想再回顾一下,网上搜到的文章都是罗列新语言特性1、2、3,贴心一点的会为每个新特性配一段代码,只是每次看一段新代码,自己都要经历一个"重启"的过程,感觉会消耗过多的发迹线,于是我尝试着写一段代码,尽量囊括所有新的语言特性。

我对这段代码的要求如下:

  1. 不定义新的 struct/class (用std::pair来代替)
  2. 不定义新的 function
  3. 用STL
  4. 用双重循环打印一个数字三角形

下面所有的工作都是在 wandbox.org 完成的。打开网页就能编辑/编译,并可以选用c++03/14/17的编译器,可以说是非常贴心了。

一段代码展示 C++11/14/17 的语言特性_第1张图片
Photo by Émile Perron on Unsplash

C++03 的代码

作为比较,先看看代码的原始形态

#include 
#include 
#include 

using namespace std;

int main()
{
  vector<pair<int, string> > v;  
     
  v.push_back(pair<int, string>(1, "a")); 
  v.push_back(pair<int, string>(2, "b")); 
  v.push_back(pair<int, string>(3, "c")); 
  v.push_back(pair<int, string>(4, "d")); 
  v.push_back(pair<int, string>(5, "e")); 
  
  for (vector<pair<int, string> >::iterator it = v.begin(); it < v.end(); it++) {
    for (vector<pair<int, string> >::iterator it2 = v.begin(); it2 <= it; it2++) {
      cout << "(" << it2->first << "," << it2->second << ") "; 
    }
    cout << endl;
  }
}

上面这段代码输出是:

(1,a)
(1,a) (2,b)
(1,a) (2,b) (3,c)
(1,a) (2,b) (3,c) (4,d)
(1,a) (2,b) (3,c) (4,d) (5,e)

C++11/14的代码

注意:

  1. 下面的这段代码精华在注释
  2. 搜索[c++11]查看具体的语言特性
  3. 尽量做到每一行都有用
#include 
#include 
#include  // std::find
#include  // std::shared_ptr

using namespace std;

int main(void)
{
  using T = pair<int, string>; // for clearer code demo
  vector<T> v = {{1, "a"}, {2, "b"}, {3, "c"}, {4, "d"}, {5, "e"}}; // [C++11]Bracketed copy-list-initialization   // NO-Range-Operator

  auto p(make_shared<T>(6, "f")); // [C++11]shared_ptr: use 'make_shared' instead of 'new'
  v.push_back(move(*p)); // only demo, don't do like this. [C++11]Move semantic, check the effect in the last line // Note: std containers already impleted move sematics
    
  for(auto& m: v) { // [C++11]Type Deduction (auto), [C++11]Range Based For-Loop   // NO-(index, value)-pair-iteration
    for_each(begin(v), find(v.begin(), v.end(), m)+1, [&m](auto n) { // generic begin(), [C++11]Lamda
      if (m.first == n.first) m.second = m.second + to_string(m.first); // verify m is a reference
      cout << "(" << m.first << "," << m.second << ")-(" << n.first << "," << n.second << ") "; // NO-String-Interpolation...
    });
    cout << endl;
  }

  cout << p->first << "-" << p->second << endl; // check the move effect. results based on compiler & flags
  p = nullptr; // use nullptr instead of NULL
  return 0;
}

上面这段代码输出是:

(1,a1)-(1,a)
(2,b)-(1,a1) (2,b2)-(2,b)
(3,c)-(1,a1) (3,c)-(2,b2) (3,c3)-(3,c)
(4,d)-(1,a1) (4,d)-(2,b2) (4,d)-(3,c3) (4,d4)-(4,d)
(5,e)-(1,a1) (5,e)-(2,b2) (5,e)-(3,c3) (5,e)-(4,d4) (5,e5)-(5,e)
(6,f)-(1,a1) (6,f)-(2,b2) (6,f)-(3,c3) (6,f)-(4,d4) (6,f)-(5,e5) (6,f6)-(6,f)
6-

从输出结果可以看出:

  1. m 是 pass by reference, n 是 pass by value,所以每一行的最后一个输出(即,满足条件m.first == n.first 时),n 的 string 没有受到影响
  2. std::move 将原始数据的 string 部分给移走了,所以最后一行输出为空

C++17的代码

重要的仅有一行,见注释

#include 
#include 
#include 

using namespace std;

int main(void)
{
  vector<pair<int, string>> v = {{1, "a"}, {2, "b"}, {3, "c"}, {4, "d"}, {5, "e"}};
  
  for(auto& m: v) {
    for_each(begin(v), find(v.begin(), v.end(), m)+1, [&m](auto n) {
      if (auto &[p, q] = m; p == n.first) q = q + to_string(p); // [C++17]structured binding, [C++17]Init statements for if/switch
      cout << "(" << m.first << "," << m.second << ")-(" << n.first << "," << n.second << ") "; 
    });
    
    cout << endl;
  }

  return 0;
}

上面这段代码输出是:

(1,a1)-(1,a)
(2,b)-(1,a1) (2,b2)-(2,b)
(3,c)-(1,a1) (3,c)-(2,b2) (3,c3)-(3,c)
(4,d)-(1,a1) (4,d)-(2,b2) (4,d)-(3,c3) (4,d4)-(4,d)
(5,e)-(1,a1) (5,e)-(2,b2) (5,e)-(3,c3) (5,e)-(4,d4) (5,e5)-(5,e)

一行代码展示两个特性,不错不错。

总结

近来用 Swift 比较多,因此昨天写这些代码时难免有些比较

  1. C/C++ 效率总是第一位的,很高兴看到 move semantics 继续在这方面努力。近来看帖子似乎不少人觉得算力过剩,程序只要写起来爽,运行慢点无所谓。觉得算力过剩的人,真怀疑是不是学计算机的;至于写起来爽和运行快,这是不冲突的,需要的是编译器的努力和语言特性的改进。这正是C++11/14/17在做的
  2. 在上面C++11/14的代码中,有几个注释以 NO- 开头的,是 Swift 中有的一些语法特性,很好用,但 C++ 现在还没有
  3. auto 似乎的确有点多,都成段子了。而 Swift 也是强调 Type Deduction 的,代码看起来似乎没那么刺眼

附C++黑话

  • Rule of 5 (创建类时需要考虑的): Classes that have custom destructors, copy/move constructors or copy/move assignment operators should deal exclusively with ownership.
  • RAII (资源分配时需要考虑的): Resource Acquisition Is Initialization, is a C++ programming technique which binds the life cycle of a resource that must be acquired before use to the lifetime of an object.
  • RTTI: Run-Time Type Identification, refers to the ability of the system to report on the dynamic type of an object and to provide information about that type at runtime

你可能感兴趣的:(c++,编程)