现代C++改变了什么
C 是一门古老的语言, C++在为C 引入了面向对象和泛型,也引入了许多的复杂性,例如多重继承,模板的特化,等等。同时 C++ 本身除了 STL 标准库,缺少高质量的并发和网络软件包,每个C++程序员或多或少都造过大大小小的轮子。
例如我就写过很多 string 处理的函数, 比如 Trim, LowerCase, UpperCase, 等等,还有基于引用计数的智能指针,包装 pthread 函数的线程类,林林总总,各种轮子都要自己和团队手工打造。有时有点成就感,可是显然也拖慢了开发速度,自己的轮子虽然够用,可是并非考虑周全,异常保护不够,经常会挖坑,也让别人踩坑。
所以近年来,逐渐在项目中引入 boost 库来提高开发效率,也从 C++ 98 向 C++11, 14, 17, 乃至 C++ 20 过渡。
在 C++ 11、14、17、20 中我们可以看到很多 boost library 的影子, 例如 boost::shared_ptr, boost::thread , boost::random, 等等。
C++ 11 新特性
改进的对象构造
- 继承基类的构造函数
- 默认的成员值
- 委托构造函数
- overwrite 关键字
- final 关键字
- 统一的初始化 {}
其他语言增强
- 基于范围的 for 循环
- long long int 类型 (64位)
- lambda 函数
- 移动语义和右值引用
- 强类型枚举: enum 增加了类型检查
- 智能指针
- 原始字符串字面量
- 静态断言
- 可变参数模板
- 改善了右尖括号的处理
新的关键字
- auto 自动类型推导
- constexpr: 表达式常量
- decltype: 声明类型
- nullptr: 空指针
- thread_local: 线程局部存储
对 C++ 库的增强
- stl 容器的列表初始化
- 随机库
- 正则表达式库
- 无序容器(hash)
- 附加的算法
- 元组模板
- 其他的新类型: chrono(时间测量), ratio(有理数分数), complex(复数)
作为一个 Java/C++ 都时常用到的老程序员,委托构造函数,智能指针,lambda 等许多东西都不新鲜,唯独需要重点提到的是右值。
C++ 本来就已经很复杂了,为什么又要弄出来右值这个东西来烧脑呢? 原因还是在于对于压榨出高性能的需求,就象Linux 系统命令 cp
和 mv
, 原先的值拷贝好比 cp
, 现在的右值用于移动语义好比 mv
。
什么是右值,一句话,有名字的是左值,没名字的右值,就因为右值没有名字,它们都是一个临时的变量,对于它们的复制可以简化为移动,反正临时的无名变量没人会用到。
例子代码
- 头文件
run_example.h
#ifndef RUN_EXAMPLE_H_
#define RUN_EXAMPLE_H_#include <stdio.h>
#include <stdint.h>#include <string>
#include <map>
#include <iostream>
#include <memory>#include <unordered_map>
#include <boost/log/trivial.hpp>
#include <boost/program_options.hpp>
#include <boost/core/noncopyable.hpp>
#include <boost/assert.hpp>//old function pointer
typedef int (*exam_func_ptr)(int argc, char** argv);
//new function object
typedef std::function<int(int, char**)> exam_func_t;template<typename T, typename... Ts>
std::unique_ptr<T> my_make_unique(Ts&&... params) {return std::unique_ptr<T>(new T(std::forward<Ts>(params)...));
}class Command
{
public:Command();Command(std::string name);Command(const Command& other);Command& operator=(const Command& other);Command(Command&& other);Command& operator=(Command&& other);virutal ~Command();void setName(const std::string& name);void setParameter(const std::string& name, const std::string& value);void setData(const uint8_t* pData, size_t length);friend std::ostream& operator<<(std::ostream&, const Command& obj);private:std::string m_name = "";std::map<std::string, std::string> m_parameters;size_t m_length = 0;uint8_t* m_data = nullptr;
};class ExampleRunner: boost::noncopyable {
public:ExampleRunner();//no need by noncopyable//ExampleRunner(const ExampleRunner& rhs);//ExampleRunner& operator=(const ExampleRunner& rhs);virtual ~ExampleRunner();void init();size_t size() const;void register_example(const std::string& name, const exam_func_t &exam);int execute_example(const std::string& name, int argc, char** argv) const;
private:volatile uint32_t m_example_count = 0;std::unordered_map<std::string, exam_func_t> m_func_examples;
};#endif
- 实现文件
run_example.cpp
#include "run_example.h"using namespace std;
namespace po = boost::program_options;extern int function_demo(int argc, char** argv);
extern int lambda_demo(int argc, char* argv[]);
extern int rvalue_demo(int argc, char* argv[]);
extern int smart_ptr_demo(int argc, char** argv);const int CASE_COUNT =4;const char* usage = R"name(please specify example name:function_demoor lambda_demoor rvalue_demoor smart_ptr_demo
)name";//C++11: delegate constructor
Command::Command():Command("") {BOOST_LOG_TRIVIAL(trace) << "line " <<__LINE__<< ". construct: " << m_name << "@" <<this;
}Command::Command(string name):m_name(name) {BOOST_LOG_TRIVIAL(trace) << "line " <<__LINE__<< ". construct: " << m_name << "@" <<this;
}Command::Command(const Command& other) {BOOST_LOG_TRIVIAL(trace) << "line " <<__LINE__<< ". copy construct: " << m_name << "@" <<this;m_name = other.m_name;for (const auto& kv : other.m_parameters) {BOOST_LOG_TRIVIAL(trace) << kv.first << " has value " << kv.second;m_parameters.insert(kv);}std::copy(other.m_data, other.m_data + m_length, m_data);
}Command& Command::operator=(const Command& other) {BOOST_LOG_TRIVIAL(trace) << "line " <<__LINE__<< ". operator =: " << other.m_name;if (this != &other){this->m_name = other.m_name;for (const auto& kv : other.m_parameters) {std::cout << kv.first << " has value " << kv.second << std::endl;m_parameters.insert(kv);}// Free the existing resource.if(m_data) {delete[] m_data;}m_length = other.m_length;m_data = new uint8_t[m_length];std::copy(other.m_data, other.m_data + m_length, m_data);}return *this;
}Command::Command(Command&& other) {BOOST_LOG_TRIVIAL(trace) << "line " <<__LINE__<< " move copy construct: " << other.m_name << "@" <<this;m_name = std::move(other.m_name);m_parameters = std::move(other.m_parameters);// Copy the data pointer and its length from the source object.m_data = other.m_data;m_length = other.m_length;// Release the data pointer from the source object so that// the destructor does not free the memory multiple times.other.m_data = nullptr;other.m_length = 0;}Command& Command::operator=(Command&& other)
{BOOST_LOG_TRIVIAL(trace) << "line " <<__LINE__<< " move operator ==" << other.m_name;if (this != &other){m_name = std::move(other.m_name);m_parameters = std::move(other.m_parameters);// Free the existing resource.delete[] m_data;// Copy the data pointer and its length from the// source object.m_data = other.m_data;m_length = other.m_length;// Release the data pointer from the source object so that// the destructor does not free the memory multiple times.other.m_data = nullptr;other.m_length = 0;}return *this;
}Command::~Command() {BOOST_LOG_TRIVIAL(trace) << "line " <<__LINE__<< ". destruct: " << m_name ;
}void Command::setName(const string& name) {m_name = name;
}
void Command::setParameter(const string& name, const string& value) {m_parameters[name] = value;
}void Command::setData(const uint8_t* pData, size_t length) {BOOST_LOG_TRIVIAL(trace) << "line " <<__LINE__<< ". setData: " << m_name;if(nullptr != m_data) {delete[] m_data;}m_length = length;m_data = new uint8_t[length];std::copy(pData, pData + length, m_data);
}ostream& operator<<(ostream& os, const Command& obj)
{os << obj.m_name;os << ": ";//for (map<string, string>::iterator it = obj.m_parameters.begin(); it != obj.m_parameters.end(); ++it)for (const auto& kv : obj.m_parameters){os << kv.first << "=" << kv.second << endl;}for(size_t i=0; i< obj.m_length; ++i) {os << *(obj.m_data + i);}return os;
}ExampleRunner::ExampleRunner(): m_example_count(0),m_func_examples() {BOOST_LOG_TRIVIAL(trace)<<"* ExampleRunner construct: " ;
}ExampleRunner::~ExampleRunner() {BOOST_LOG_TRIVIAL(trace)<<"* ExampleRunner destruct: ";
}void ExampleRunner::init() {register_example("function_demo", function_demo);register_example("smart_ptr_demo", smart_ptr_demo);register_example("lambda_demo", lambda_demo);register_example("rvalue_demo", rvalue_demo);
}void ExampleRunner::register_example(const string& name, const exam_func_t &exam)
{m_example_count++;m_func_examples[name] = exam;
}int ExampleRunner::execute_example(const string& name, int argc, char** argv) const
{auto it = m_func_examples.find(name);if(it != m_func_examples.end()) {BOOST_LOG_TRIVIAL(trace) << "execute "<< it->first;exam_func_t func = it->second;return func(argc, argv);}BOOST_LOG_TRIVIAL(trace) << "not registered "<< name;return -1;
}size_t ExampleRunner::size() const {return m_func_examples.size();
}int main(int argc, char** argv)
{unique_ptr<ExampleRunner> runner = my_make_unique<ExampleRunner>();runner->init();BOOST_ASSERT_MSG(runner->size()==CASE_COUNT, "example count should be 2");//c++11 R"raw string"po::options_description desc("Allowed options:");desc.add_options()("help,h", "produce help message")("name,n", po::value<string>(), usage);po::variables_map vm;po::store(po::parse_command_line(argc, argv, desc), vm);po::notify(vm); if (vm.count("help")) {BOOST_LOG_TRIVIAL(trace) << desc << "\n";return 1;}if (vm.count("name")) {BOOST_LOG_TRIVIAL(trace) << "* example name is "<< vm["name"].as<string>() << ".";runner->execute_example(vm["name"].as<string>(), argc, argv);} else {BOOST_LOG_TRIVIAL(trace) << "example name was not set.";BOOST_LOG_TRIVIAL(trace) << desc ;}return 0;
}
关于智能指针和移动拷贝的例子
- boost_memory.cpp
#include "run_example.h"using namespace std;int rvalue_demo(int argc, char* argv[])
{//move constructorCommand cmd1(Command("c1"));//copy constructorCommand cmd2 = cmd1;shared_ptr<Command> sharedPtr = make_shared<Command>("update");sharedPtr->setParameter("user", "alice");uint8_t nBytes[3] = { 0x00,0x01,0x02 };sharedPtr->setData(nBytes, 3);shared_ptr<Command> sharedPtr2 = sharedPtr;BOOST_LOG_TRIVIAL(trace) << "line " <<__LINE__ << ". sharedPtr=" << sharedPtr.get() << ", "<< sharedPtr.use_count() <<", command="<< *sharedPtr;BOOST_LOG_TRIVIAL(trace) << "line " <<__LINE__ << ". sharedPtr2=" << sharedPtr2.get() << ", "<< sharedPtr2.use_count() <<", command="<< *sharedPtr2;return 0;
}int smart_ptr_demo(int argc, char* argv[])
{BOOST_LOG_TRIVIAL(trace) << "line " <<__LINE__ << " -- unique_ptr --";//unique_ptr<Command> ptr = unique_ptr<Command>(new Command());unique_ptr<Command> uniquePtr = my_make_unique<Command>();uniquePtr->setName("create");uniquePtr->setParameter("user", "walter");BOOST_LOG_TRIVIAL(trace) << "line " <<__LINE__ << ". unique pointer=" << uniquePtr.get() <<", command="<< *uniquePtr;BOOST_LOG_TRIVIAL(trace) << "line " <<__LINE__ << ". -- shared_ptr --";shared_ptr<Command> sharedPtr = make_shared<Command>();sharedPtr->setName("retrieve");sharedPtr->setParameter("user", "walter");BOOST_LOG_TRIVIAL(trace) << "line " <<__LINE__ << ". shared pointer=" << sharedPtr.get() << ", "<< sharedPtr.use_count() <<", command="<< *sharedPtr;return 0;
}
运行结果
./bin/run_example -n rvalue_demo
[2020-10-07 13:59:40.303527] [0x0000000107d9edc0] [trace] * ExampleRunner construct:
[2020-10-07 13:59:40.304168] [0x0000000107d9edc0] [trace] * example name is rvalue_demo.
[2020-10-07 13:59:40.304179] [0x0000000107d9edc0] [trace] execute rvalue_demo
[2020-10-07 13:59:40.304198] [0x0000000107d9edc0] [trace] line 27. construct: c1@0x7ffeed644df0
[2020-10-07 13:59:40.304204] [0x0000000107d9edc0] [trace] line 61 move copy construct: c1@0x7ffeed644db0
[2020-10-07 13:59:40.304210] [0x0000000107d9edc0] [trace] line 100. destruct:
[2020-10-07 13:59:40.304234] [0x0000000107d9edc0] [trace] line 31. copy construct: @0x7ffeed644df0
[2020-10-07 13:59:40.304255] [0x0000000107d9edc0] [trace] line 27. construct: update@0x7faa5c407408
[2020-10-07 13:59:40.304264] [0x0000000107d9edc0] [trace] line 112. setData: update
[2020-10-07 13:59:40.304281] [0x0000000107d9edc0] [trace] line 19. sharedPtr=0x7faa5c407408, 2, command=update: user=alice[2020-10-07 13:59:40.304289] [0x0000000107d9edc0] [trace] line 20. sharedPtr2=0x7faa5c407408, 2, command=update: user=alice[2020-10-07 13:59:40.304295] [0x0000000107d9edc0] [trace] line 100. destruct: update
[2020-10-07 13:59:40.304315] [0x0000000107d9edc0] [trace] line 100. destruct: c1
[2020-10-07 13:59:40.304319] [0x0000000107d9edc0] [trace] line 100. destruct: c1
[2020-10-07 13:59:40.304327] [0x0000000107d9edc0] [trace] * ExampleRunner destruct:
参考资料
- https://www.modernescpp.com/index.php/what-is-modern-c
- https://github.com/lefticus/cppbestpractices
- https://github.com/isocpp/CppCoreGuidelines
http://www.taodudu.cc/news/show-6465526.html
相关文章:
- 用java有理数类包含加减乘除,7.1 面向对象的简介 - VimL 语言编程指北路
- 2.6_4 Reids数据类型 + 基础命令
- 分数四则运算java_用java具体代码实现分数(即有理数)四则运算
- matlab显示格式,Matlab基础学习-----数据显示格式(设置)
- C++ : Boost : Rational 有理数类
- MATLAB学习第二天(基础语法、变量、命令以及新建自己文件)
- matlab命令整理-1
- 学习笔记 Matlab 命令 -4
- 4.MATLAB常用命令
- linux中l没有ll命令,manjaro linux没有ll等命令的解决办法
- 应用逻辑:haskell生成有理数集合
- 分类梨和苹果的两种方法
- c语言孔融分梨函数代码,孔融分梨
- PTA-孔融分梨(函数实现)
- 小孩儿吃梨问题c语言,C语言编程练习 6.2课上编程练习.docx
- PTA 7-207 孔融分梨(函数实现)
- 7-207 孔融分梨(函数实现)
- 入门级动态规划-分梨
- 动态规划(分梨、最长公共子序列)
- 练习题 G: 分梨
- 中国大学MOOC第六周作业孔融分梨
- dp专题:分梨
- 分梨(简单递归)
- 7-207 孔融分梨(函数实现)7-208 sdut-C语言实验- 数列求和2
- 孔融分梨c语言
- c语言函数孔融分梨,ACM题目:孔融分梨
- c语言编码孔融分梨,孔融分梨的故事
- 【递归问题】分梨
- 孔融分梨1
- 题解:分梨----递归,动态规划
现代C++改变了什么相关推荐
- 点击改变div高度_css实现div两列布局(两种方法)
一.应用场景 左侧一个导航栏宽度固定,右侧内容根据用户浏览器窗口宽度进行自适应 二.思路 首先把这个问题分步解决,需要攻克以下两点: 1.让两个div并排到一行 2.让一个div宽度固定,另个div占 ...
- 解决LC_ALL: 无法改变区域选项 (UTF-8): 没有那个文件或目录的问题
问题: -bash: 警告:setlocale: LC_ALL: 无法改变区域选项 (UTF-8): 没有那个文件或目录 -bash: 警告:setlocale: LC_ALL: 无法改变区域选项 ( ...
- Qt中如何改变三角形图形项的包围盒
Bounding Rect 和 Shape 的联系与区别 Bounding Rect 将 item 的外边界定义为矩形,所有绘制必须限制在此区域内,QGraphicsView 使用它来确定 item ...
- 改变自己,让自己变得更好
在现实生活中,有些时候我们会想着去改变别人,希望别人能顺从自己一点,这样心里会好受一些:但往往让我们想不到的是,每个人都有自己的想法,都有自己的主见: 并不是每个人都能理解你,都会按你的意愿去顺从你的 ...
- 人要懂得放下已经发生,却又无法改变的事情
在生活中,有些事情如果注定是无法改变的,那么就尽可能快的释怀,要坦然接受,坚强的走出来.毕竟很多事情,不会因为你的悲伤,结果就会改变. 不如,果断看开放下,然后收拾心情重新开展好的事情发展.未来的路还 ...
- 在批评中改变自己,才能真正取得进步
在工作中难免会遇到上司批评时候,而批评一般有两种:有一种批评是带有情绪的批评,这种批评往往来自于你的上司,因为你工作上的问题激怒了你的上司. 当你面对这样的批评时要微笑,然后倾听,这个时候千万不要辩解 ...
- view(*args)改变张量的大小和形状_pytorch reshape numpy
20201227 这个方法是在不改变数据内容的情况下,改变一个数组的格式,参数及返回值,官网介绍: a:数组–需要处理的数据 newshape:新的格式–整数或整数数组,如(2,3)表示2行3列,新的 ...
- Android ListView 点击item改变item的背景颜色(ListView实现光标移动)
一下demo 地址 实现的效果图如下 ListView 光标移动,实现很是简单,这里是指item背景的改变 使用 listSelector listSelector 用户指定当前选中item 的颜色 ...
- Ubuntu 系统禁止或者改变中文简体切换繁体,方便使用AS全局搜索
使用Ubuntu 系统 开发的我们在使用android studio 或者idea 在使用全局搜索的时候发现确实切换中文简体字和繁体字 很烦闹,自己也不使用繁体字就把切换禁止了算了 下面说下禁止的方法 ...
- js 点击改变内容与vue 点击改变内容
js 的代码如下 <!DOCTYPE html> <html><head><meta charset="UTF-8"><tit ...
最新文章
- 年终总结,程序员票选最喜欢的编程语言花落谁家?
- js、jquery实用小技巧集合
- Bootstrap的轮播图
- Linux 命令之 curl -- 文件传输工具/下载工具/网络接口调试
- 【POJ - 3310】Caterpillar(并查集判树+树的直径求树脊椎(bfs记录路径)+dfs判支链)
- webpack打包原理
- 在Hadoop集群实施成功后再次格式化名称节点,datanode无法加入集群的处理办法
- 农艺师需要职称计算机,评农艺师需要发表几篇论文?
- Java native方法String转char*以及String[]转char**
- 《大型数据库技术》MySQL管理维护
- docker制作python项目镜像
- 有关液压的相关知识(1)-螺纹与齿轮泵
- AI学习路线和书籍分享
- 分享PHP多功能在线工具箱网站源码,安装教程详解
- Latex学习之插入编号-实心圆点列表,横杆,数字
- SNAT、DNAT、MASQUERADE的区别
- java课程设计 计算器_Java课程设计-计算器
- winimage使用教程
- python给excel排序_用python处理excel数据(六)实现excel表中排序功能
- 基于javaweb+jsp的鲜花花卉销售管理系统(JavaWeb MySQL JSP Bootstrap Servlet SSM SpringBoot)
热门文章
- 如何从详情页获取淘宝/天猫商品的分类?
- linux nvidia 361.run,Ubuntu 16.04+Nvidia GTX 1080+CUDA8.0 深度学习环境配置
- 宣传部第二学期第一次培训
- 22071班(11月29日)
- B2B电子商务策略[在2022年发展您的业务]
- DLNA DMR实现
- oracle scn超了,Oracle安全 - SCN的可能最大值与耗尽问题
- 【驱动代码移植高通平台之二十三】高通平台i2c设备驱动
- 未来计算机发展趋势作文,未来的计算机作文300字(精选3篇)
- Opportunity