1.编译原理

2.语言可用性的强化

2.1常量

  1. nullptr

    nullptr 的出现主要是替换NULL,在C语言中NULL表示的是(void*(0)),而在C++ 中表示0,
    C++ 不允许直接将void* 隐式转换到其他类型

// #define NULL 0
// 导致C++ 重载特性发生混乱
void test(char*);
void test(int);
test(NULL);

因此C++ 引入nullptr 区分0 和 空指针, nullptr的类型是nullptr_t 可以隐式转换成任意类型的指针

#include <iostream>
#include <type_traits>using namespace std;void test(int i){cout <<__FUNCTION__ <<endl;
}
void test(char *){cout <<__FUNCTION__ <<endl;
}
int main(){if (is_same<decltype(NULL),decltype(0)>::value)cout << "NULL == 0" <<endl;if (is_same<decltype(NULL),decltype(void*(0))>::value)cout << "NULL == void*(0)" <<endl;if (is_same<decltype(NULL),decltype(nullptr_t)>::value)cout << "NULL == nullptr_t" <<endl;   test(0);test(nullptr);// test(NULL);return 0;
}
  1. constexpr

    const 作为常量, 而constexpr 是修饰常量表达式,即在编译前可以确定表达式的值;

constexpr int getNum(){return 10;
}
const int num = 10;
constexpr int sum = num * 2;
int g_list[sum]={0};
const len = num + 2;
char arr_4 [len]; // 数组的长度必须是一个常量表达式

2.2 变量及其初始化

  1. if/switch 变量声明强化
    if 和 switch 中无法声明一个变量
// C++ 17 中是允许的
if ( const auto itr = std::find( vec.begin (), vec.end() , 3); 3 itr != vec . end () ) {* itr = 4;
}
  1. 初始化列表
    std::initializer_list
    内置类型可以直接使用;
class MagicFoo {public:vector<int> m_vec;// 初始化列表构造函数MagicFoo(initializer_list<int> list) {for (auto it = list.begin(); it != list.end(); ++it) {m_vec.emplace_back(*it);}}
};
int main()
{MagicFoo magicFoo = { 1,2,3,4,5 };MagicFoo magicFoo2{ 1,2,3,4,5 };int data{10};return 0;
}
  1. 结构化绑定
    std::tuple
// C++17的支持
#include <tuple>std::tuple<int, double, std::string> f() {return std::make_tuple(1, 2.0, "test");
}
int main()
{auto [x, y, z] = f();cout << x << "-" << y << "-" << z << endl;return 0;
}

2.3 类型推导

  1. auto
    auto 作为静态类型推导,不可以作为函数的参数
// 在函数的para 有默认值时可以使用
int test(auto data = 0) {return data;
}
test(10); // auto 还不能用于推导数组类型auto arr = new auto (10);auto data[20] = arr;
  1. decltype 推导表达式的类型
auto x = 10;
decltype(x) y=20;
  1. 尾返回类型推导
//
template < typename R , typename T , typename U >
R add ( T x , U y ) reurn x+y;
/*这样的写法并不能通过编译。这是因为在编译器读到 decltype(x+y) 时,x 和 y 尚未被定义
*/
decltype ( x + y ) add(T x, U y )// C++14 开始是可以直接让普通函数具备返回值推导
// 尾返回类型(trailing return type)
template <typename T , typename U >
auto add ( T x , U y ) -> decltype(x+y) reurn x+y;
  1. decltype(auto)
    decltype(auto) 主要用于对转发函数或封装的返回类型进行推导,无需显示的指定decltype的参数
string getString();
decltype(auto) get_string_test()return getString();

2.4 控制流

  1. if constexpr
template <typename T>
auto print_type_info(const T& t) {if constexpr (is_integral_v<T>) {return t + 1;} else {return t + 0.01;}
}
int main()
{cout << print_type_info(1) << endl;    // 2cout << print_type_info(1.0) << endl;     // 1.01return 0;
}
  1. 区间for迭代
vector<string> t;
for(string temp : t);
for(auto temp : t);

2.5 模板

C++ 模板能够将一切能够在编译器处理的事情在编译器处理,并且模板和泛型编程息息相关

  1. 外部模板
    模板在被使用的才会被编译器实例化,项目中每次使用到的模板在编译器被实例化,会造成代码的编译时间增加,
    C++11 引入外部模板,可以显示的通知编译器进行模板的实例化
template class vector<bool>; // 强行实例化
extern template class vector<double>; // 不在当前编译文件中实例化模板
  1. 尖括号 “>”

位运算符>>
前期模板中的 vector<vector > 最后的>> 是需要程序员自己增加空格
C11 之后vector<vector> 变得合法化了

  1. 类型别名模板
// typedef  和 using
using callback = std::function<void(string,int)>;
typedef void(*callback)(string,int);
  1. 默认模板参数
template <class T = int, class TT = float>
auto add(T x, TT y) ->decltype(x+y)return x+y;
  1. 变长参数模板
 template < typename Require , typename ... Args > class Magic {public:Magic(Args ...args){std :: cout << sizeof ...( args ) << std :: endl ;}  }

5.1 递归模板函数

template <typename T >
void printf(T value) {std::cout << value << std::endl;}
template < typename T, typename ... Args >
void printf(T value, Args ... args) {std::cout << value << std::endl;printf(args ...);}int main()
{printf(1, 2, "123 ", 1.1);return 0;
}// C17
template < typename T0 , typename ... T >
void printf ( T0 t0 , T ... t ) {std :: cout << t0 << std :: endl ;if constexpr ( sizeof ...( t ) > 0) printf ( t ...) ;
}

5.2 初始化列表展开

template < typename T , typename ... Arg >
void printf ( T t ,  Arg... args ) {std :: cout << value << std :: endl ;return std :: initializer_list <T >{([&] {std :: cout << args << std :: endl ;}() , value ) ...};
}
print (1 , 2.1 , "123 ");

5.3 折叠表达式

// c17
template < typename ... T >
auto sum ( T ... t ) {return ( t + ...) ;
}
sum (1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10)

2.6 面向对象

  1. 委托构造
// 委托构造 简化代码
class Base {public:int m_val;int m_data;Base() :m_val(m_val) {}Base(int data) : Base() {m_data = data;}Base(int val, int data) : Base(data) {m_val = val;}
};
  1. 继承构造
// 继承构造
class Base {public:int m_val;std::string m_data;Base() {m_val = 1;}Base(std::string data) :Base() {m_data = data;}
};class Subclass :public Base {public:using Base::Base;};
  1. 显式虚函数重载 override final virtual
struct Base {virtual void foo();
};struct SubClass : Base {virtual void foo() override;
};struct  BaseFinal {// 禁止被重载virtual void foo() final;
};
// 禁止被继承
struct SubClassFinal final : BaseFinal {};
  1. 显式禁用默认函数
class Magic {public:Magic() = default;Magic& operator=(const Magic&) = delete;Magic(Magic&) = default;Magic(Magic&&) = default;~Magic() = default;
};
  1. 强类型枚举
enum class new_enum : unsigned int {value1,value2,value3 = 100,value4 = 200
};template <typename T>
std::ostream& operator<<(typename std::enable_if<std::is_enum<T>::value,std::ostream>::type& stream, const T& e) {return stream << static_cast<typename std::underlying_type<T>::type>(e);
}int main()
{cout << new_enum::value4 << endl;return 0;
}

3 语言运行期的强化

3.1 Lambda表达式

捕获列表 mutable(可选)->返回值类型{ 函数体};
捕获列表 值捕获= 引用捕获& 变量捕获 空捕获列表
C14 表达式捕获

   auto important = std::make_unique<int>(1);auto add = [v1 = 1, v2 = std::move(important)](int x, int y)->int{return x + y + v1 + (*v2);};cout << add(3, 4) << endl;

泛型 Lambda(C14)
auto add = [](auto x,auto y){ return x+y; }

3.2 函数对象包装器

lambda 表达式的本质是一个和函数对象类型相似的类类型的对象,当捕获列表为空的时候还可以转换为函数指针进行传递

  1. std::function
// C++11 std::function 是一种通用、多态的函数封装
using foo = std::function<void(int)>; // using foo = void(int);
void functional(foo f) {return f(1);
}int main()
{auto f = [](int value) {cout << value << endl;};functional(f);f(1);return 0;
}
  1. std::bind/std::placeholder
int foo(int a, int b) {return a + b;
}int main()
{auto bindFoo = std::bind(foo, std::placeholders::_1, 2);cout << bindFoo(1) << endl;return 0;
}
  1. 右值引用
/*
左值 右值的纯右值 将亡值 右值
左值表达式后依然存在的持久对象
右值表达式结束后不存在的临时对象
纯右值字面量和匿名的临时对象 lambda表达式都是纯右值
将亡值即将被销毁,却能够被移动的值*/
void reference(string& str) {cout << "左值" << endl;
}
void reference(string&& str) {cout << "右值" << endl;
}int main()
{string lv1 = "string";string&& rv1 = std::move(lv1);const string& lv2 = lv1 + lv1;string&& rv2 = lv1 + lv1;reference(rv2);    // 左值return 0;
}

4.移动语义

class A {public:int* m_ptr;A() :m_ptr(new int(1)) {cout << "构造" << "  " << m_ptr << endl;}A(A& a) :m_ptr(new int(*a.m_ptr)) {cout << "拷贝" << "  " << m_ptr << endl;}A(A&& a) :m_ptr(a.m_ptr) {cout << "移动" << "  " << m_ptr << endl;}~A() {cout << "析构" << "  " << m_ptr << endl;}
private:};
// 防止编译器优化
A return_rvalue(bool test) {A a, b;if (test)return a;return b;
}int main()
{A obj = return_rvalue(false);cout << obj.m_ptr << endl;cout << *obj.m_ptr << endl;return 0;
}/*
*  首先会在 return_rvalue 内部构造两个 A 对象,于是获得两个构造函数的输出;
*  函数返回后,产生一个将亡值,被 A 的移动构造(A(A&&))引用,从而延长生命周期,并将这个右值
*  中的指针拿到,保存到了 obj 中,而将亡值的指针被设置为 nullptr,防止了这块内存区域被销毁
*/

5.完美转发
完美转发就是在传递参数的时候保持原来的参数类型

void reference(int& v) {cout << "左值" << endl;
}void reference(int&& v) {cout << "右值" << endl;
}
template <typename T>
void pass(T&& v) {reference(v);reference(std::move(v));reference(std::forward<T>(v));cout << endl << endl;
}
int main()
{pass(1);int v = 10;pass(v);return 0;
}

4.容器

4.1 std::array 和 std::forward_list

引入arrayforward_list 能够让代码变得更现代化,并且使代码更加安全,同时还能够友好的使用标准库中的容器算法, 使用array 的时候要兼顾C风格的接口

forward_list 底层是由单向链表进行实现;不提供size接口;

4.2 无序容器

有序容器map/set* 这些元素内部通过红黑树进行实现,
无序容器中的元素是不进行排序的,内部通过Hash 表实现,在不关心容器内部元素顺序时,能够获得显著的性能提升
unordered_map/unordered_mutimap/unordered_set/unordered_multiset

4.3 元组 tuple

元组的三个核心的函数
1.make_tuple: 构造元组
2.get : 获得元组某个位置的值
3.tie: 元组拆包

#include <tuple>auto getStudent(int id) {if (id == 0) {return std::make_tuple(3.8, 'A', "张三");}if (id == 1) {return std::make_tuple(4.8, 'B', "李四");}return std::make_tuple(0.0, 'N', "null");
};int main()
{auto student = getStudent(0);cout << "data: "<< "  GPA: " << get<0>(student)<< "  成绩: " << get<1>(student)<< "  姓名: " << get<1>(student)<< endl;double gpa;char grade;string name;std::tie(gpa, grade, name) = getStudent(1);cout << "data: "<< "  GPA: " << gpa<< "  成绩: " << grade<< "  姓名: " << name<< endl;return 0;}// 合并元组
auto newTuple = tuple_cat(getStudent(1),move(t));
// 遍历元组
template <typename T>
auto tupleLen(T &tpl){return std::tuple_size<T>::value;
}for(int i=0;i!=tupleLen(newTuple);++i){cout << tuple_index(i,newTuple)<<endl;
}

5.指针

5.1 RAII 与引用计数

  • 引用计数是为了防止内存泄漏,
  • 在构造函数中申请内存,在析构函数中释放,也就是RAII 资源获取即初始化
  • C11引入智能指针,使用引用计数的想法,让程序中不在需要关注手动释放内存

5.2 shared_ptr

shared_ptr 内部使用引用计数,当引用计数为0的时候,就会将对象自动删除
// 初始化的两种方式
std::shared_ptrstd::string s1(new string(“123”));
std::shared_ptrstd::string s2 = std::make_sharedstd::string(“1234”);
// 获取对象的原始指针
string* origin = s2.get();
// 减少引用计数
s2.reset();
// 获取对象被引用的个数
s2.use_count();

5.3 unique_ptr

//std::unique_ptr是一种独占的智能指针,禁止其他智能指针与其共享同一个对象,从而保证代码的安全
std::unique_ptr<int> p = std::make_unique<int>(10);      // c14
// 移动权限
auto data = std::move(p);
// make_unique_ptr 实现机制
template <typename T, typename ...Args>
std::unique_ptr<T> my_make_unique(Args&& ...args) {return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

5.4 weak_ptr

// shared_ptr 循环引用问题
// 循环引用struct A;
struct B;struct B {using Ptr = std::shared_ptr<B>;A::Ptr _ptr;~B() {cout << "~B()" << endl;}
};struct A {using Ptr = std::shared_ptr<A>;B::Ptr _ptr;~A() {cout << "~A()" << endl;}
};int main()
{A::Ptr a = std::make_shared<A>();B::Ptr b = std::make_shared<B>();a->_ptr = b;b->_ptr = a;return 0;
}


// 解决这个问题的办法就是使用弱引用指针std::weak_ptr,弱引用不会引起引用计数增加

6.正则表达式

6.1 正则表达式简介

普通字符
特殊字符
限定符

6.2 std::regex 及其相关

7.线程与并发

7.1 thread

#include <thread>
void foo() {cout << "test thread" << endl;
}int main()
{std::thread t(foo);t.join();return 0;
}

7.2 std::mutex, std::unique_lock

#include <thread>
#include <mutex>#define LOCK_GURAD(x) std::lock_guard<decltype<x>> lk(x)// 发生异常 锁没有被释放
void someOperator(const string& message) {static std::mutex mtx;LOCK_GURAD(mtx);
}
// unique_lock std::mutex mtx;
void block_area() {std::unique_lock<std::mutex> lock(mtx);lock.lock();lock.unlock();
}int main()
{std::thread t(block_area);t.join();return 0;
}

7.3 std::future, std::packaged_task

/*
* std::future 提供了一个访问异步操作结果的途径;
* 问题: 试想我们的主线程A 希望开辟一个线程B 去执行某个我们预期的任务,并返回一个结果
* 解决方案: 线程A 中启动任务B,执行完成后发送一个事件执行结果保存在某个全局变量中,当线程A
*   想要执行结果时,调用一个线程等待的函数获取结果
*
* std::future简化此流程,可以用来获取异步任务的结果,是一种线程同步的方法
* std::packaged_task 可以用来封装任何可以调用的目标,从而实现异步调用
*
*/int main()
{std::packaged_task<int()> task([]() {return 7; });std::future<int> result = task.get_future();std::thread(std::move(task)).detach();std::cout << "waiting...";result.wait();cout << "Done :" << result.get() << endl;return 0;
}

7.4 std::condition_variable

#include <thread>
#include <mutex>
#include <future>
#include <condition_variable>
#include <queue>
#include <chrono>/*std::condition_variable 是为了解决死锁而生的,当互斥锁的引入而不够实现场景功能时问题: 线程A 可能等待某个条件为真才能继续执行,而一个忙等待循环中可能会导致其他所有线程都无法进入临界区使条件为真就会发送死锁,解决方法: condition_variable实例被创建出现主要就是用于唤醒等待线程从而避免死锁std::condition_variable的notify_one和notify_all 就是为了解决此问题*/
// int main()
{// 生产者的数量std::queue<int> producedNums;std::mutex m;std::condition_variable condVar;// 结束标志bool done = false;// 通知标志bool notified = false;// 生产者线程std::thread producer([&] {for (size_t i = 0; i < 5; ++i) {std::this_thread::sleep_for(std::chrono::seconds(1));std::unique_lock<std::mutex> lk(m);cout << "producing  " << i << endl;producedNums.emplace(i);notified = true;condVar.notify_one();}done = true;notified = true;condVar.notify_one();});// 消费者线程std::thread consumer([&]() {std::unique_lock<std::mutex> lk(m);while (!done) {while (!notified) {// 循环避免虚假唤醒condVar.wait(lk);}while (!producedNums.empty()) {cout << " cosuming   " << producedNums.front() << endl;producedNums.pop();}notified = false;}});producer.join();consumer.join();return 0;
}

8. 文件系统

8.1 std::filesystem

9. 其他

9.1 新类型

cout << sizeof(long long int) << endl; // 8

9.2 noexcept 的修饰和操作

// noexcept 修饰完一个函数之后能够起到封锁异常扩散的功效,如果内部产生异常,外部也不会触发
void divid(int a,int b) {if (b == 0)throw std::invalid_argument("0");
}void test() noexcept {return;
}

9.3 字面量

  1. 原始字符串字面量 去除转义限制
    std::string str = R"(C\User\Desktop)";
  2. 自定义字面量
/*自定义字面量支持四种字面量* 整形字面量:重载时必须使用 unsigned long long、const char *、模板字面量算符参数* 浮点型字面量:重载时必须使用 long double、const char *、模板字面量算符* 字符串字面量:必须使用 (const char *, size_t) 形式的参数表* 字符字面量: 参数只能是 char, wchar_t, char16_t, char32_t 这几种类型*/std::string operator"" _wow1(const char* wow1, size_t len) {return std::string(wow1) + "wooooooow, amazing";
}
std::string operator"" _wow2(unsigned long long i) {return std::to_string(i) + "wooooooow, amazing";
}int main()
{auto str = "abc"_wow1;auto num = 1_wow2;cout << str << endl;cout << num << endl;return 0;
}

C20

读书笔记<高速上手C11 14 17>相关推荐

  1. 读书笔记 | 墨菲定律

    1. 有些事,你现在不做,永远也不会去做. 2. 能轻易实现的梦想都不叫梦想. 3.所有的事都会比你预计的时间长.(做事要有耐心,要经得起前期的枯燥.) 4. 当我们的才华还撑不起梦想时,更要耐下心来 ...

  2. 读书笔记 | 墨菲定律(一)

    1. 有些事,你现在不做,永远也不会去做. 2. 能轻易实现的梦想都不叫梦想. 3.所有的事都会比你预计的时间长.(做事要有耐心,要经得起前期的枯燥.) 4. 当我们的才华还撑不起梦想时,更要耐下心来 ...

  3. 洛克菲勒的38封信pdf下载_《洛克菲勒写给孩子的38封信》读书笔记

    <洛克菲勒写给孩子的38封信>读书笔记 洛克菲勒写给孩子的38封信 第1封信:起点不决定终点 人人生而平等,但这种平等是权利与法律意义上的平等,与经济和文化优势无关 第2封信:运气靠策划 ...

  4. 股神大家了解多少?深度剖析股神巴菲特

    股神巴菲特是金融界里的传奇,大家是否都对股神巴菲特感兴趣呢?大家对股神了解多少?小编最近在QR社区发现了<阿尔法狗与巴菲特>,里面记载了许多股神巴菲特的人生经历,今天小编简单说一说关于股神 ...

  5. 2014巴菲特股东大会及巴菲特创业分享

     沃伦·巴菲特,这位传奇人物.在美国,巴菲特被称为"先知".在中国,他更多的被喻为"股神",巴菲特在11岁时第一次购买股票以来,白手起家缔造了一个千亿规模的 ...

  6. 《成为沃伦·巴菲特》笔记与感想

    本文首发于微信公众帐号: 一界码农(The_hard_the_luckier) 无需授权即可转载: 甚至无需保留以上版权声明-- 沃伦·巴菲特传记的纪录片 http://www.bilibili.co ...

  7. 读书笔记002:托尼.巴赞之快速阅读

    读书笔记002:托尼.巴赞之快速阅读 托尼.巴赞是放射性思维与思维导图的提倡者.读完他的<快速阅读>之后,我们就可以可以快速提高阅读速度,保持并改善理解嗯嗯管理,通过增进了解眼睛和大脑功能 ...

  8. 读书笔记001:托尼.巴赞之开动大脑

    读书笔记001:托尼.巴赞之开动大脑 托尼.巴赞是放射性思维与思维导图的提倡者.读完他的<开动大脑>之后,我们就可以对我们的大脑有更多的了解:大脑可以进行比我们预期多得多的工作:我们可以最 ...

  9. 读书笔记003:托尼.巴赞之思维导图

    读书笔记003:托尼.巴赞之思维导图 托尼.巴赞的<思维导图>一书,详细的介绍了思维发展的新概念--放射性思维:如何利用思维导图实施你的放射性思维,实现你的创造性思维,从而给出一种深刻的智 ...

  10. 产品读书《滚雪球:巴菲特和他的财富人生》

    作者简介 艾丽斯.施罗德,曾经担任世界知名投行摩根士丹利的董事总经理,因为撰写研究报告与巴菲特相识.业务上的往来使得施罗德有更多的机会与巴菲特亲密接触,她不仅是巴菲特别的忘年交,她也是第一个向巴菲特建 ...

最新文章

  1. 第三部分:Android 应用程序接口指南---第一节:应用程序组件---第七章 App Widgets...
  2. adb下载、安装、环境配置
  3. 2013应届毕业生“艺龙旅行网”校招应聘总结
  4. 小布语音下载安装_小布语音助手
  5. Cocos2d之Box2d基础知识
  6. android 图片存取方法,6种备份Android照片的方法
  7. [XJTUSE]计算机图形学第二章作业,使用OpenGL编程实现DDA、中点画线和Bresenham算法和中点画圆法
  8. 树莓派raspberryPI-4b 官方镜像raspios-bullseye-arm64 系統下编译构建ros2 rolling环境(附下载完整镜像资料)
  9. HarmonyOS的定义是什么?
  10. 计算机毕业论文致谢信范文,论文致谢信10篇
  11. Android之讯飞语音-文字转语音(不用另外安装语音合成包apk)遇到的问题
  12. 《成语接龙》隐私说明
  13. CentOS8(8.2)安装mysql8
  14. win7英文版很多软件中文显示乱码解决方案
  15. 互联网标准技术架构图
  16. 工程制图计算机考试题库,工程制图—考试题库及答案(106页)-原创力文档
  17. 再获肯定,云畅科技旗下腾云畅翼入榜2021腾讯云启创新生态企业年度榜单
  18. Flutter 之 Scaffold
  19. 电线电缆知识全面总结
  20. 随需而变,拥抱CMMI V2.0新时代

热门文章

  1. 只需三步,快速新建连接SSH客户端
  2. 简述3DES加密算法
  3. 【python】记忆和装饰器
  4. Android插件化
  5. nyoj744 蚂蚁的难题(一)
  6. 你突然对我说,七里香的名字很美
  7. python 散点图 置信区间_stata如何生成带置信区间的散点图
  8. CoreData - 查询
  9. 搜索Gif动图API
  10. Ant Design入门