C++书上的小知识点笔记

小知识点:

每个线程都必须有一个初始函数,新线程的执行开始于初始函数。对于第一段程序来说,它的初始函数是main,对于我们新创建的线程,可以在std::thread()对象的构造函数中指定。
在第二段程序里,程序由两个线程组成:初始线程始于main,新线程始于hello。这里将新线程t的初始函数指定为hello。
新线程启动之后会与初始进程一并运行,初始线程可以等待或不等待新进程的运行结束——如果需要等待线程,则新线程实例需要使用join(),否则可以使用detach()。如果不等待新线程,则初始线程自顾自地运行到main()结束。

# include
# include
using namespace std;
void hello()
{
    cout<<"hello world"<

iostream “流”就是一个字符序列,表达的是:随着时间的推移,字符是顺序生成或消耗的

std::endl的作用不仅仅是结束当前行,也有刷新缓冲区的作用
应该保证每次cout后都刷新流否则若程序崩溃,输出可能还残留在缓冲区中,导致关于程序崩溃位置错误的推断

初始化不是赋值,初始化含义是创建变量时赋予其一个初始值,而赋值含义是把对象的当前值擦除并用新值替代

尽量初始化每一个内置类型的变量

初始化所有指针,若有必要声明空指针,则尽量int *p = nullptr; 而不使用老式的null

extern int i; //声明i,而非定义i
int j; //声明并定义j,任何包含了显示初始化的声明即为定义

.#ifndef DECLARE_CLASS_H //防止多次包含同一头文件,名字全部大写
 .#define DECLARE_CLASS_H
...
.#endif

头文件中不应包含using声明

如果表达式中已经有了size()函数,就不要在使用int了
这可以避免混用int和unsigned可能带来的问题,例如:
auto len = line.size(); //len的类型是string::size_type 一个无符号的整型
也就是说要避免无符号和有符号的数据在一起运算
所有用于存放string类的size()函数返回的变量,都应该是string::size_type类型的

对于C++来说,应尽量使用不带.h的头文件,以减少不必要的麻烦

现代C++来说,尽量使用string、vector和迭代器,避免使用数组、指针和C风格字符串

但凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素

C++中string对象大小比较,两字符串自左向右逐个字符相比(按ASCII值大小相比较)

使用数组初始化vector对象:

int int_arr[] = {0,1,2,3,4,5};
//C++11中新定义的begin()和end()函数
vector v(begin(int_arr), end(int_arr)); 

内存的基本单元是位(bit),相当于开关,关=0、开=1
字节(byte)通常指8位的内存单元
1 KB = 1024 BYTE
1 MB = 1024 KB
sizeof()返回字节数

VS屏蔽4786警告 #pragma warning (disable:4786)

头文件climits定义了所有C++符号常量 例如:#define INT_MAX 32767

cout << hex; 以十六进制数输出
cout << dec; 以十进制数输出
cout << oct; 以八进制数输出

不要返回一个局部变量的指针或引用,因为得到的指针所指内容在函数结束后就已变了

//此引用不会修改实参的值,因为有const限制,当程序试图修改str时,编译器将报错
char * StringToCharPtr(const string &str); 
//此引用将会改变实参的值
char * StringToCharPtr(string &str);       

尽可能的将引用参数声明为const

为什么要返回引用? 效率更高,例如:
double m = sqrt(16.0);
传统返回:计算return后的表达式,将结果4复制到一个临时位置,然后再传递给m
返回引用:计算return后的表达式,将结果直接复制给接收的变量
注: 返回引用的函数实际上是被引用的变量的别名

避免返回临时变量的引用和指向临时变量的指针
因为临时变量存放在栈中,函数执行完毕会自动销毁,所以其引用和指针包含的数据都是错的

比如只是在函数中定义 int a;那这是个临时变量是在栈中的,使用完自动销毁;
比如定义是int *a; a=new int[10]; 那这个是分配在堆中的,使用完需要手动释放,防止内存泄漏。
1、栈区(stack)编译器自动分配释放,存放函数的参数值,局部变量的值等
2、堆区(heap) 程序员分配释放,若程序员不释放,程序结束时可能由os回收

何时使用引用参数?
程序员能够修改调用函数中的数据对象
通过传递引用而不是整个数据对象,可以提高程序的运行速度

什么时候使用按值传递?什么时候使用引用参数?什么时候使用指针参数?
1.数据对象很小,如内置数据类型或小型结构,则按值传递
2.数据对象是数组,则使用指针,因为指针可以移动并将指针声明为指向const的指针
3.数据对象是较大的结构,则使用const指针或const引用,节省复制结构的时间和空间
4.数据对象是类,则使用const引用,类设计的语义常要求使用引用,这是C++新增这项特性的主要原因。因此,传递类对象的标准方式是按引用传递。

如果 int sub(); 是一个函数,则sub即是该函数的内存地址

press(sub()) //传递函数sub()的返回值给函数press()
press(sub) //传递函数sub()的地址给函数press()

函数指针的声明:
double pam(int);
double (pf)(int);
pam是函数,所以(
pf)也是函数。 (pf)是函数,则pf就是函数指针
为了提供正确的运算符优先级,必须在声明中使用括号将
pf括起来。括号的优先级比运算符高,
因此,
pf(int)意味着pf(int)是一个返回double指针的函数,而(pf)(int)意味着pf是一个指向函数的指针
double (
pf)(int); 意味着pf是一个指向函数的指针
double pf(int); 意味着pf(int)是一个返回double指针的函数
正确的声明pf后,便可以将相应函数的地址赋给它:
double pam(int);
double (
pf)(int);
pf = pam;
注意,pam()的参数和返回值必须与pf相同,否则编译器将拒绝这种赋值

typedef double real 创建double类型的别名"real"

"Pizaa" C++解读"Pizaa"为其元素的第一个内存地址,为取值,所以*"Pizaa" = P
"Taco"[2] C++解读"Taco"为其元素的第一个内存地址,所以"Taco"[2] = c
也就是说,字符串常量的行为与数组相同

char name[30];
string str = "James";
name = str; 此种赋值的方式是错误的,正确的赋值方法应该是: strcpy/strcpy_s(name,str);
在VS2015中,编译strcpy函数会报C4996
'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
将strcpy(name,str)修改为strcpy_s(name,str);
类似的错误,也同样发生在其它很多的老式C语言函数身上,解决办法是更改为C++的函数版本.
在C语言中数组是不容许整体复制的!
故: name = str; / MyStruct.name=str; 这样的数组赋值是不正确的
表明上看这句话只是把一个地址给他,实际上要求的是数组的整体复制。
因为数组的地址是const的,不能改变。数组是可以当指针用,但只能是const指针。
两种解决方法:
1、把char name[30]修改为char* name;
2、把equal函数中的 get.name=str;修改为 strcpy(get.name, str);

size()是取字符串长度的,跟length()用法相同
length()是沿用C语言的习惯而保留下来的,string类最初只有length(),引入STL之后,为了兼容又加入了size(),
它是作为STL容器的属性存在的,便于符合STL的接口规则,以便用于STL的算法。
string类的size()/length()方法返回的是字节数,不管是否有汉字。

sizeof(...)是运算符,其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等
它的功能是:获得保证能容纳实现所建立的最大对象的字节大小。由于在编译时计算,
因此sizeof不能用来返回动态分配的内存空间的大小

类型强制转换:
C风格:
int x = 65;
char c = (char)x;
C++风格:
int x = 90;
char c = char(x);
static_cast(x); char = 转换后的类型 x = 待转换的变量或表达式

C++11新特性:

typedef double wages; //wages是double的别名
typedef double wages base, *p; //base是double的别名,p是double*的别名
using SI = Sales_item;         //C++11新标准,SI是Sales_item的别名
SI item1,item2;               //等价于Sales_item item1,item2;

aoto value = val1 + val2; //根据val1 + val2的结果推断value的类型

decltype(function()) sum = x; //sum的类型就是function()函数的返回值类型,编译器不会执行function()函数

decltype(expression) var 适用于模板函数内无法确定返回值类型的情况

template 

void templateFunction(T1 x, T2 y)
{
decltype(x + y) sum = x + y;  //如果没有decltype sum则无法确定究竟是什么类型
//auto sum = x + y;             此问题用auto关键字也有同样的效果
}

auto templateFunction(T1 x, T2 y) -> decltype(x + y)  解决无法定义返回值类型的问题
{
decltype(x + y) sum = x + y;  //如果没有decltype sum则无法确定究竟是什么类型
//auto sum = x + y;             此问题用auto关键字也有同样的效果

int *p = new int;
delete p;
p = nullptr;
最好将释放的指针设置为空,以便程序后续可以检测到该指针已经被释放

for(declaration : expression) //迭代expression对象中的所有元素
{
statement
}

string str = "some string!"; //迭代str中的所有元素
    for (auto c : str)
        cout << c << endl;

如果我们想要修改str的元素该如何操作呢?答案是利用引用:
for (auto &c : str) 此时c是str当前元素的引用,所以修改c,也就是修改了str内的元素,示例:

//迭代str中的所有元素,并且当元素为小写字母时,通过修改str元素的引用c来达到修改str元素为大写字母的目的
string str = "Some String!"; 
for (auto &c : str)
{
    if (islower(c))
    {
        c = toupper(c);
    }
    cout << c << " ";
}

C++11定义了begin()和end()函数,使用方法和STL中的同名类函数类似,示例:头文件

int ia[] = {0,1,2,3,4,5,6,7,8,9};
int *beg = begin(ia);  //指向ia首元素的指针
int *last = end(ia);   //指向数组尾元素的下一位置的指针(和STL中vector v; v.end()的意思是一样的)

常用英文单词:

英文 中文
preprocessor 预处理器
header guard 头文件保护符
header 头文件
expression 表达式
initialize 初始化
identifier 标识符
operator 运算符
scope 作用域
null pointer 空指针
assignment 赋值
comments 注释
variable 变量
function 函数
method 方法
member 成员
object 对象
argument 实参
declaration 声明
definition 定义
condition 条件
default 默认
value
reference 引用
alias 别名
bind 绑定
integral 整型
convert 转换
vector 向量
container 容器
index 索引
address 地址
library
buffer 缓冲
block 程序块
manipulator 操作符
built-in type 内置类型
data structure 数据结构
edit-compile-debug 编辑-编译-调试

未完

你可能感兴趣的:(C++书上的小知识点笔记)