一段代码展示 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的编译器,可以说是非常贴心了。

Photo by Émile Perron on Unsplash
Photo by Émile Perron on Unsplash

C++03 的代码

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

#include <iostream>
#include <cstdlib>
#include <vector>

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 <iostream>
#include <vector>
#include <algorithm> // std::find
#include <memory> // 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 <iostream>
#include <algorithm>
#include <vector>

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值