类型转换
切勿混用无符号类型和有符号类型
表达式中两者都有时,有符号类型会转化为无符号类型,当该值为负时会出现非预期结果;
unsigned a = 1; int b = -1; cout<<a*b;//输出 4294967295
//详解: b的源码:100...1 负数转补码按位取反加1后为:1111...0 无符号类型把该值读出为4294967295 (结果视所在机器位数而定)
无符号类型用于循环时注意其永远不会小于0的特性
转义序列和指定类型
注意:“\1234” 前3个构成转义序列八进制对应的asill值
注:表示长整型时用L而不是小写 l 它和 1 容易弄混;
后缀的存在是为了明确指示字面值的数据类型,从而避免编译器的隐式类型转换或产生二义性。然而,并非所有数据类型都需要后缀,因为它们的类型可以根据字面值的形式自动推断出来。此外,使用错误的后缀可能导致编译错误或运行时错误,因此需要小心使用。C++弄啥呢?这玩意儿真的是服了,哎
(a) 字符 宽字符型字符(wchar_t类型) 字符串 宽字符型字符串
(b) 整数 无符号数 长整数 无符号长整数 八进制数 十六进制数
(c) 浮点型 单精度浮点型 long double类型的扩展精度浮点型
(d) 整数 无符号整数 浮点数 科学计数法表示的浮点数
变量初始化 不等于 赋值 (初始化是创建变量并赋予一个初始值,赋值是擦除当前值用新值代替)
变量声明 规定了变量类型和名字,定义 除此之外还申请了存储空间,可能还会赋初始值。(建议初始化每一个内置类型的变量)
extern int i; //声明 i
int j;//声明并定义 j
extern int k = 3; //赋初始值抵消了extern的作用变成了定义,且如果是在函数内部初始化extern标记的变量会报错
变量必须且只能在一个文件中定义一次,其他文件中使用到该变量的必须进行声明,却绝对不能重复定义!(变量能且只能被定义一次,但是可以被多次声明)
标识符的命名规范
由字母、数字、下划线组成,且必须以字母或下划线开头。
不能作标识符规范
- 一些作为C++语言的使用的关键字,如if、int、false等
- 一些作为C++标准库的保留字,不能连续两个下画线,不能下画线连大写字母开头,
- 定义在函数体外的标识符不能以下划线开头
推荐的标识符规范
- 见名知义,能体现实际含义好懂
- 变量名小写字母,如 index
- 类名大写字母开头,如Index
- 标识符多字母组成采用下划线分割或大写字母开头分割,如student_loan_up或studentLoanUp
作用域
全局作用域和块作用域
作用域嵌套,外层作用域声明某名字,其嵌套的作用域也就是内作用域都能访问该名字,同时允许内层作用域重新定义外层作用域已有的名字。
引用和指针的主要区别
- 引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
- 不能有 NULL 引用,引用必须与合法的存储单元关联(指针则可以是 NULL)。
- 一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。
https://www.runoob.com/w3cnote/cpp-difference-between-pointers-and-references.html
使用未经初始化的指针容易引发错误,因此不知道指向具体对象时初始化为nullptr ,如:int *p = nullptr;
因此要判断一个指针是否指向合法地址,判断是不是nullptr即可,或者如果没有初始化指针的话可以try…catch是否出错。
void* 是一种特殊的指针类型,可以存放任意对象的地址。
int* p和 int *p的问题,其实基本类型是int的p是指向int的指针;所以建议采用第二种写法,int *p1, *p2;
指向指针的指针,为了访问原始对象,需要解引用两次;
指向指针的引用,引用本身不是对象因此不能定义指向引用的指针,但是指针是对象,所以存在对指针的引用;
int i = 33;
int *p;//int 类型的指针p
int *&r = p;//从右往左看,r 是 对指针p的引用
r = &i;//r是指向p的引用,给r赋值&i 就是让p指向i
*r = 0;//解引用 r 得到 i,也就是p指向的对象,改i的值为0
面对复杂的指针或引用声明语句时,从右向左阅读有助于弄清真实含义;
定义一个const变量在多个文件中声明并使用它的方法是,不管是定义还是声明都加extern关键字;
extern const int bufsize = fcn();//1.cc定义并初始化一个常量,并让该常量能被其他文件访问
** 底层const和顶层const? **
常量表达式:值不会改变并且编译过程就能得到计算结果的表达式
比如 const staff_size = get_size(); 就是不是,因为其到运行时才能获取到,const int limit = 20;才是常量表达式
C++11 :如果你认定变量是一个常量表达式,那就把它声明成 constexpr 类型;
auto类型推导
1、使用引用作初始值时,以引用对象的类型作为auto的类型;
int i = 0, &r = i;
auto a = r; //a 类型为 int
2、auto会忽略顶层const、保留底层const;
auto &h = 42; //非常量引用需要绑定一个可修改的对象;
const auto &j = 42;
基于C++14/17的Http应用框架Drogon: https://github.com/drogonframework/drogon/blob/master/README.zh-CN.md(《权力的游戏》中的一条龙的名字(汉译作卓耿))
grpc翻译的中文文档:https://doc.oschina.net/grpc?t=58008 (跨平台 的RPC框架),解释:https://juejin.cn/post/7047885453336248327
腾讯开源的rpc框架phxrpc:https://gitee.com/mirrors/PhxRPC#https://gitee.com/link?target=https%3A%2F%2Fgithub.com%2FTencent%2Fphxrpc%2Fwiki
https://github.com/Tencent/phxrpc
(*it).empty(); 简化后it->empty();
凡是使用了迭代器的循环体,都不要向迭代器所属容器添加元素;
比如push_back可能导致vector对象的迭代器失效;
比如范围for循环向vector添加元素
空指针是指向null的指针用于内存初始化指针变量,内存编号0~255是系统占用内存不可访问;
野指针是指向非法的内存空间的指针,两者访问应该都会报错,但是在Dev下运行如下代码:编译无误还能运行,只不过会无输出,运行一段时间后窗口自动关闭,这是为什么?
#include <bits/stdc++.h>
using namespace std;
int main(){
int a = 10;
int *p = NULL;
cout << *p <<endl;
int *q = (int *)0x1110;
cout << *q <<endl;
return 0;
}
虽然语法无误可以通过编译器,但是由于解引用空指针和野指针导致的内存访问违例,操作系统为了保护系统终止了该程序的执行。
机器真正的存法:正数直接存,负数保留符号位按位取反+1;
大端序是网络中普遍用的符合人类阅读习惯,小端序大多数个人PC用的,符合机器;
这个非常重要一定要注意!!!
Redis中设计的sdshdr结构体有个len变量存字符串长度,不用遍历去算;有个free管理剩余容量,如果容量不够会自动扩容并修改len大小;
指针和引用
指针的数组(array of pointers),这个数组里一个个的都是指针 。 T *t[ ]
数组的指针(a pointer to an array),这一个指针指向一个数组。T (*t) [ ]
第三个例子先看第一个const修饰的左边char表示指针的值不可改,再看第二个const修饰的*,表示指针的指向不能改;
const修饰指针有三种情况
- const修饰指针 — 常量指针(指针指向可改,指向的值不可改)
- const修饰常量 — 指针常量(指针指向不可改,指针的值可以改)
- const即修饰指针,又修饰常量(都不能改)
看const右侧紧跟着的是指针还是常量, 是指针就是常量指针,是常量就是指针常量
const常用来防止误操作
RALL
智能指针
内存模型
内存泄漏