cpp回顾

兼容c

1
2
3
4
5
6
7
8
9
#ifdef __cplusplus
extern "C"{
#endif
void func(int x,int y);
#ifdef __cplusplus
}
#endif
//__cplusplus 是由c++编译器定义的宏,用于表示当前处于c++环境

引用

引用只能传是已经分配内存的变量,而指针可以传空指针。

1
2
3
4
5
6
7
//声明形参为引用
void change(int& i) {
i = 10;
}
int i = 1;
change(i);
printf("%d\n",i); //i == 10

浅拷贝深拷贝

像以下这样的代码默认会进行一次浅拷贝,浅拷贝只会把值复制一份,对于指针也是把原来的内存地址复制了一遍并不会开拓新的内存空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Student {
public:
int i; //默认 private
int *j = 0;
Student(int i , int j) {
this->i = i;
this->j = new int(1);
*(this->j) = j;
}; //构造方法 i(i) 代表this->i=i
~Student() {
delete(j);
j = 0;
}; //析构方法
};
int main()
{
Student s1(1,2);
Student s2 = s1;
printf("%d---%d\n", s1.i, *s1.j);
printf("%d---%d\n", s2.i, *s2.j);
s2.i = 3;
*s2.j = 4;
printf("%d---%d\n", s1.i, *s1.j);
printf("%d---%d\n", s2.i, *s2.j);
system("pause");
return 0;
}
输出
1---2
1---2
1---4
3---4

而需要把指针也拷贝一份需要重写默认的拷贝函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class Student {
public:
int i; //默认 private
int *j = 0;
Student(int i , int j) {
this->i = i;
this->j = new int(1);
*(this->j) = j;
}; //构造方法 i(i) 代表this->i=i
Student(Student &t) {//&t是旧的那个类
i = t.i;
j = new int;
*j = *t.j;
cout << "深拷贝" << endl;
}
~Student() {//析构方法
cout << "析构" << endl;
delete(j);
j = 0;
};
};
int main()
{
Student s1(1,2);
Student s2 = s1;
printf("%d---%d\n", s1.i, *s1.j);
printf("%d---%d\n", s2.i, *s2.j);
s2.i = 3;
*s2.j = 4;
printf("%d---%d\n", s1.i, *s1.j);
printf("%d---%d\n", s2.i, *s2.j);
system("pause");
return 0;
}
输出
1---2
1---2
1---2
3---4

析构函数

析构函数在对象消亡时即自动被调用。可以定义析构函数在对象消亡前做善后工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Student {
int i; //默认 private
public:
Student(int i=2,int j,int k=3):i(i),j(j),k(k){}; //构造方法 i(i) 代表this->i=i
~Student(){}; //析构方法
private:
int j;
protected:
int k;
};
Student student(1,2,3); //调用构造方法 栈
//出方法释放student 调用析构方法
//动态内存(堆)
Student *student = new Student(1,2,3);
//释放
delete student;
student = 0;

常量函数

函数后写上const,表示不会也不允许修改类中的成员。

1
2
3
4
5
6
7
8
9
10
class Student {
char *name;
public:
// 常量函数
void setName(char* _name) const {
//错误 不能修改name 去掉const之后可以
name = _name;
}
};

友元

友元函数

类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Student {
int i;
public:
friend void printName(Student *student);
private:
int j;
char *name;
protected:
int k;
};
void printName(Student *student) {
//能够使用student中私有的name属性
cout << student->name << endl;
}
Student *student = new Student;
student->setName("Lance");
printName(student);

友元类

若一个类愿意将自身的所有成员属性和函数(包含私密的)分享给另一个类可使用友元类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Student {
public:
//友元类
friend class Teacher;
private:
int j;
char *name;
void setName(char* _name) {
name = _name;
}
protected:
int k;
};
class Teacher {
public:
void call(Student *student) {
//能够使用student中私有的name属性
cout << "call:" << student->name << endl;
}
};

静态类静态函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#pragma once
class Instance {
private:
static Instance* instance;
Instance();
public:
static Instance* getInstance();
};
//////////////////////////////////////////////////
#include "Instance.h"
Instance * Instance::instance = 0;
Instance::Instance() {
}
Instance* Instance::getInstance() {
if (!instance)
{
instance = new Instance;
}
return instance;
}

重载

函数重载

1
2
3
4
5
6
7
void print(int i) {
cout << "整数为: " << i << endl;
}
void print(double f) {
cout << "浮点数为: " << f << endl;
}

操作符重载

C++允许重定义或重载大部分 C++ 内置的运算符

函数名是由关键字 operator 和其后要重载的运算符符号构成的

重载运算符可被定义为普通的非成员函数或者被定义为类成员函数 、

例子

1
2
3
4
5
Test2 operator+(const Test2& t21, const Test2& t22) {
Test2 t;
t.i = t21.i + t22.i;
return t;
}

允许重载的运算符

类型 运算符
关系运算符 ==(等于),!= (不等于),< (小于),> (大于>,<=(小于等于),>=(大于等于)
逻辑运算符 \ \ (逻辑或),&&(逻辑与),!(逻辑非)
单目运算符 + (正),-(负),*(指针),&(取地址)
自增自减运算符 ++(自增),–(自减)
位运算符 \ (按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移)
赋值运算符 =, +=, -=, *=, /= , % = , &=, \ =, ^=, <<=, >>=
空间申请与释放 new, delete, new[ ] , delete[]
其他运算符 ()(函数调用),->(成员访问),,(逗号),

继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Parent {
public:
void test() {
cout << "parent" << endl;
}
};
class Child : Parent {
public:
void test() {
// 调用父类 方法
Parent::test();
cout << "child" << endl;
}
};

虚函数

虚函数 防止子类向上转型动态指向父类的函数 析构函数一般要定义为虚函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Parent {
public:
void test() {
cout << "parent" << endl;
}
};
class Child :public Parent {
public:
void test() {
cout << "child" << endl;
}
};
Parent *c = new Child();
// 编译期间 确定c 为 parent 调用parent的test方法
c->test();
//修改Parent为virtual 虚函数 动态链接,告诉编译器不要静态链接到该函数
virtual void test() {
cout << "parent" << endl;
}
//动态多态 调用Child的test方法
c->test();

纯虚函数

纯虚函数 类似java的抽象方法 声明函数

1
2
3
4
5
6
7
8
9
10
class Parent {
public:
//纯虚函数 继承自这个类需要实现 抽象类型
virtual void test() = 0;
};
class Child :public Parent {
public:
void test(){}
};

模板

模板是泛型编程的基础

函数模板

函数模板能够用来创建一个通用的函数。以支持多种不同的形參。避免重载函数的函数体反复设计。

1
2
3
4
5
6
7
8
9
template <typename T>
T max(T a,T b)
{
// 函数的主体
return a > b ? a : b;
}
//代替了
int max(int a,int b)
int max(float a,float b)

类模板(泛型类)

为类定义一种模式。使得类中的某些数据成员、默写成员函数的參数、某些成员函数的返回值,能够取随意类型

常见的 容器比如 向量 vector 或 vector 就是模板类

1
2
3
4
5
6
7
8
9
10
template<class E,class T>
class Queue {
public:
T add(E e,T t){
return e+t;
}
};
Queue<int,float> q;
q.add(1,1.1f) = 2.1f

类型转换

除了能使用c语言的强制类型转换外,还有:转换操作符 (新式转换)

const_cast

修改类型的const或volatile属性

1
2
3
4
5
const char *a;
char *b = const_cast<char*>(a);
char *a;
const char *b = const_cast<const char*>(a);

static_cast

  1. 基础类型之间互转。如:float转成int、int转成unsigned int等
  2. 指针与void之间互转。如:float*转成void*、Bean*转成void*、函数指针转成void*等
  3. 子类指针/引用与 父类指针/引用 转换。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Parent {
public:
void test() {
cout << "p" << endl;
}
};
class Child :public Parent{
public:
void test() {
cout << "c" << endl;
}
};
Parent *p = new Parent;
Child *c = static_cast<Child*>(p);
//输出c
c->test();
//Parent test加上 virtual 输出 p

dynamic_cast

主要 将基类指针、引用 安全地转为派生类.

在运行期对可疑的转型操作进行安全检查,仅对多态有效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//基类至少有一个虚函数
//对指针转换失败的得到NULL,对引用失败 抛出bad_cast异常
Parent *p = new Parent;
Child *c = dynamic_cast<Child*>(p);
if (!c) {
cout << "转换失败" << endl;
}
Parent *p = new Child;
Child *c = dynamic_cast<Child*>(p);
if (c) {
cout << "转换成功" << endl;
}

reinterpret_cast

对指针、引用进行原始转换

1
2
3
4
5
6
7
8
9
10
float i = 10;
//&i float指针,指向一个地址,转换为int类型,j就是这个地址
int j = reinterpret_cast<int>(&i);
cout << hex << &i << endl;
cout << hex << j << endl;
cout<<hex<<i<<endl; //输出十六进制数
cout<<oct<<i<<endl; //输出八进制数
cout<<dec<<i<<endl; //输出十进制数

char*与int转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//char* 转int float
int i = atoi("1");
float f = atof("1.1f");
cout << i << endl;
cout << f << endl;
//int 转 char*
char c[10];
//10进制
itoa(100, c,10);
cout << c << endl;
//int 转 char*
char c1[10];
sprintf(c1, "%d", 100);
cout << c1 << endl;

异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void test1()
{
throw "测试!";
}
void test2()
{
throw exception("测试");
}
try {
test1();
}
catch (const char *m) {
cout << m << endl;
}
try {
test2();
}
catch (exception &e) {
cout << e.what() << endl;
}
//自定义
class MyException : public exception
{
public:
virtual char const* what() const
{
return "myexception";
}
};
//随便抛出一个对象都可以

文件与流操作

C 语言的文件读写操作

头文件:stdio.h

函数原型:FILE fopen(const char path, const char * mode);

path: 操作的文件路径

mode:模式

模式 描述
r 打开一个已有的文本文件,允许读取文件。
w 打开一个文本文件,允许写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会从文件的开头写入内容。如果文件存在,则该会被截断为零长度,重新写入。
a 打开一个文本文件,以追加模式写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会在已有的文件内容中追加内容。
r+ 打开一个文本文件,允许读写文件。
w+ 打开一个文本文件,允许读写文件。如果文件已存在,则文件会被截断为零长度,如果文件不存在,则会创建一个新文件。
a+ 打开一个文本文件,允许读写文件。如果文件不存在,则会创建一个新文件。读取会从文件的开头开始,写入则只能是追加模式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//========================================================================
FILE *f = fopen("xxxx\\t.txt","w");
//写入单个字符
fputc('a', f);
fclose(f);
FILE *f = fopen("xxxx\\t.txt","w");
char *txt = "123456";
//写入以 null 结尾的字符数组
fputs(txt, f);
//格式化并输出
fprintf(f,"%s",txt);
fclose(f);
//========================================================================
fgetc(f); //读取一个字符
char buff[255];
FILE *f = fopen("xxxx\\t.txt", "r");
//读取 遇到第一个空格字符停止
fscanf(f, "%s", buff);
printf("1: %s\n", buff);
//最大读取 255-1 个字符
fgets(buff, 255, f);
printf("2: %s\n", buff);
fclose(f);
//二进制 I/O 函数
size_t fread(void *ptr, size_t size_of_elements,
size_t number_of_elements, FILE *a_file);
size_t fwrite(const void *ptr, size_t size_of_elements,
size_t number_of_elements, FILE *a_file);
//1、写入/读取数据缓存区
//2、每个数据项的大小
//3、多少个数据项
//4、流
//如:图片、视频等以二进制操作:
//写入buffer 有 1024个字节
fwrite(buffer,1024,1,f);

C++ 文件读写操作

\ 和 \

数据类型 描述
ofstream 输出文件流,创建文件并向文件写入信息。
ifstream 输入文件流,从文件读取信息。
fstream 文件流,且同时具有 ofstream 和 ifstream 两种功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
char data[100];
// 以写模式打开文件
ofstream outfile;
outfile.open("XXX\\f.txt");
cout << "输入你的名字: ";
//cin 接收终端的输入
cin >> data;
// 向文件写入用户输入的数据
outfile << data << endl;
// 关闭打开的文件
outfile.close();
// 以读模式打开文件
ifstream infile;
infile.open("XXX\\f.txt");
cout << "读取文件" << endl;
infile >> data;
cout << data << endl;
// 关闭
infile.close();

线程

C++11线程

1
2
3
4
5
6
7
8
9
#include <thread>
void task(int i) {
cout << "task:" << i << endl;
}
thread t1(task,100);
//等待线程结束再继续执行
t1.join();

POSIX线程

POSIX 可移植操作系统接口,标准定义了操作系统应该为应用程序提供的接口标准

创建线程

方法 说明
int pthread_create(pthread_t __ pthread_ptr, pthread_attr_t const attr, void (start_routine)(void), void ); 创建线程 第一个参数为线程id,第二个参数为线程属性,第三个参数为线程要运行的函数指针,第四个参数为传给运行的函数的 参数的地址

例子

1
2
3
4
5
6
7
8
9
10
11
#include <pthread.h>
void *pthreadTask(void* args) {
int* i = static_cast<int*>(args);
cout << "posix线程:" << *i << endl;
return 0;
}
pthread_t pid;
int pi = 100;
pthread_create(&pid, NULL, pthreadTask, &pi);
//等待线程的结束
pthread_join(pid,0);

线程属性

1
2
3
4
pthread_attr_t attr;
//初始化 attr中为操作系统实现支持的线程所有属性的默认值
pthread_attr_init(&attr);
pthread_attr_destroy(&attr);

分离线程

线程创建默认是非分离的,当pthread_join()函数返回时,创建的线程终止,释放自己占用的系统资源

分离线程不能被其他线程等待,pthread_join无效。

1
2
3
//PTHREAD_CREATE_DETACHED 分离
//PTHREAD_CREATE_JOINABLE 非分离
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);

调度策略与优先级

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//设置调度策略
//返回0 设置成功
pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
// SCHED_FIFO
// 实时调度策略,先到先服务 一旦占用cpu则一直运行。一直运行直到有更高优先级任务到达或自己放弃。
// SCHED_RR
// 实时调度策略,时间轮转 系统分配一个时间段,在时间段内执行本线程
//设置优先级
//获得对应策略的最小、最大优先级
int max = sched_get_priority_max(SCHED_FIFO);
int min = sched_get_priority_min(SCHED_FIFO);
sched_param param;
param.sched_priority = max;
pthread_attr_setschedparam(&attr, &param);

线程同步

方法 说明
pthread_mutex_t 互斥锁的对象
pthread_mutex_init(pthread_mutex_t __ mutex, const pthread_mutexattr_t __attr); 初始化互斥锁 第一个参数互斥锁的对象 第二个是互斥锁属性 NULL值为默认属性
pthread_mutex_destroy(pthread_mutex_t* __mutex) 消除一个互斥锁
pthread_mutex_lock(pthread_mutex_t* __mutex) 加锁(阻塞操作 如果这个锁此时正在被其它线程占用, 那么 pthread_mutex_lock() 调用会进入到这个锁的排队队列中,并会进入阻塞状态, 直到拿到锁之后才会返回)
pthread_mutex_trylock(pthread_mutex_t* __mutex) 加锁(非阻塞操作 如果锁被占用咱就不用,如果没被占用那就用)
pthread_mutex_unlock(pthread_mutex_t* __mutex) 释放锁

非堵塞

1
2
3
4
5
6
int err = pthread_mutex_trylock(&mtx);
if(0 != err) {
if(EBUSY == err) {
//The mutex could not be acquired because it was already locked.
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
queue<int> q;
pthread_mutex_t mutex;//创建了一个互斥锁
void *pop(void* args) {
// 锁
pthread_mutex_lock(&mutex);
if (!q.empty())
{
printf("取出数据:%d\n", q.front());
q.pop();
}
else {
printf("无数据\n");
}
// 放
pthread_mutex_unlock(&mutex);
return 0;
}
int main()
{
//初始化互斥锁
pthread_mutex_init(&mutex, 0);
for (size_t i = 0; i < 5; i++)
{
q.push(i);
}
pthread_t pid[10];
for (size_t i = 0; i < 10; i++)
{
pthread_create(&pid[i], 0, pop, &q);
}
//需要释放
for (size_t i = 0; i < 10; i++)
{
pthread_join(pid[i], 0);
}
pthread_mutex_destroy(&mutex);
system("pause");
return 0;
}

条件变量

条件变量是线程同步的一种手段。条件变量用来自动阻塞一个线程,直到条件(predicate)满足被触发为止。通常情况下条件变量和互斥锁同时使用。

方法 说明
pthread_cond_t 条件变量对象
pthread_cond_init(pthread_cond_t __ cond, const pthread_condattr_t __attr) 初始化条件变量 第二个参数为NULL,则使用默认条件变量属性
pthread_cond_wait(pthread_cond_t __ cond, pthread_mutex_t __mutex) 阻塞 第一个参数为条件变量 第二个参数为互斥锁
pthread_cond_signal(pthread_cond_t* __cond) 解除阻塞 由系统通知唤醒一个线程
pthread_cond_broadcast(pthread_cond_t *cond) 解除阻塞 广播通知所有等待线程(推荐用这个)
pthread_cond_destroy(pthread_cond_t* __cond) 销毁条件变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#pragma once
#include <queue>
using namespace std;
template <class T>
class SafeQueue {
public:
SafeQueue() {
pthread_mutex_init(&mutex,0);
pthread_cond_init(&cond, 0);
}
~SafeQueue() {
pthread_mutex_destory(&mutex);
pthread_cond_destory(&cond);
}
void enqueue(T t) {
pthread_mutex_lock(&mutex);
q.push(t);
//发出信号 通知挂起线程
//由系统唤醒一个线程
//pthread_cond_signal(&cond);
// 广播 对应多个消费者的时候 多个线程等待唤醒所有
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
}
int dequeue(T& t) {
pthread_mutex_lock(&mutex);
//可能被意外唤醒 所以while循环
while (q.empty())
{
pthread_cond_wait(&cond, &mutex);
}
t = q.front();
q.pop();
pthread_mutex_unlock(&mutex);
return 1;
}
private:
queue<T> q;
pthread_mutex_t mutex;
pthread_cond_t cond;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "lsn6_example.h"
#include <thread>
#include <pthread.h>
using namespace std;
#include "safe_queue.h"
SafeQueue<int> q;
void *get(void* args) {
while (1) {
int i;
q.dequeue(i);
cout << "消费:"<< i << endl;
}
return 0;
}
void *put(void* args) {
while (1)
{
int i;
cin >> i;
q.enqueue(i);
}
return 0;
}
int main()
{
pthread_t pid1, pid2;
pthread_create(&pid1, 0, get, &q);
pthread_create(&pid2, 0, put, &q);
pthread_join(pid2,0);
system("pause");
return 0;
}

智能指针

shared_ptr

操作引用计数实现共享式拥有的概念。多个智能指针可以指向相同的对象,这个对象和其相关资源会在最后一个被销毁时释放。

1
2
3
4
5
6
7
8
9
10
11
12
class A {
public:
~A() {
cout << "释放A" << endl;
}
};
void test() {
//自动释放 引用计数为1
shared_ptr<A> a(new A());
//退出方法 shared_ptr a本身释放,对内部的 A 对象引用计数减1 则为0 释放new 出来的A 对象
}

虽然使用shared_ptr能够非常方便的为我们自动释放对象,但是还是会出现一些问题。最典型的就是循环引用问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class B;
class A {
public:
~A() {
cout << "释放A" << endl;
}
shared_ptr<B> b;
};
class B {
public:
~B() {
cout << "释放B" << endl;
}
shared_ptr<A> a;
};
void test() {
//自动释放
shared_ptr<A> a(new A()); //A引用计数为1
shared_ptr<B> b(new B()); //B引用计数为1
cout << a.use_count() << endl; //查看内部对象引用计数
a->b = b; //A 引用计数为2
b->a = a; //B 引用计数为2
//退出方法,a释放,A引用计数-1结果为1 不会释放 B也一样
}

weak_ptr

weak_ptr是为配合shared_ptr而引入的一种智能指针。主要用于观测资源的引用情况。

它的构造和析构不会引起引用记数的增加或减少。没有重载*和->但可以使用lock获得一个可用的shared_ptr对象。

配合shared_ptr解决循环引用问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class B;
class A {
public:
~A() {
cout << "释放A" << endl;
}
weak_ptr<B> b;
};
class B {
public:
~B() {
cout << "释放B" << endl;
}
weak_ptr<A> a;
};
void test() {
//自动释放
shared_ptr<A> a(new A()); //A引用计数为1
shared_ptr<B> b(new B()); //B引用计数为1
a->b = b; //weak_ptr 引用计数不增加
b->a = a; //weak_ptr 引用计数不增加
//退出方法,A B释放
}

weak_ptr 提供expired 方法等价于 use_count == 0,当expired为true时,lock返回一个存储空指针的shared_ptr

unique_ptr

实现独占式引用,保证同一时间只有一个智能指针指向内部对象。

1
unique_ptr<A> a(new A());

auto_ptr已经不推荐使用

部分C++11、14特性

nullptr

nullptr 出现的目的是为了替代 NULL。 C++11之前直接将NULL定义为 0。

1
2
3
4
5
6
7
8
9
10
void test(int* i){
}
void test(int i){
}
//现在调用哪一个test? test(int)
test(NULL);
//调用test(int* i)
test(nullptr);

类型推导

C++11 重新定义了auto 和 decltype 这两个关键字实现了类型推导,让编译器来操心变量的类型。

1
2
3
4
5
6
7
8
auto i = 5; // i 被推导为 int
auto p = new auto(10) // arr 被推导为 int *
//但是auto不能作用在数组上
auto arr1[10] = { 0 }; //错误
auto arr2= {0}; //正确
typeid(arr2).name() //获得类型名为 initializer_list(后续介绍)
// int j
decltype(i) j = 10;

基于范围的 for 循环

实际上就是foreach

1
2
3
4
5
6
vector<int> vec = { 1,2,3,4,5 };
//配合auto使用
for(auto i : vec)
{
cout << i << endl;
}

Lambda

匿名函数,即没有函数名的函数

完整形式:

[捕获外部变量列表 ] (参数列表) mutable exception->返回类型 { 函数体 }

mutable:在外部变量列表以值来捕获时,无法修改变量的值,加上mutable表示可修改(不会影响外部变量)

1
2
3
4
5
6
7
8
9
auto i = 5;
// [&] 表示外部变量都以引用的形式在lambda中使用,函数内部修改i的值会影响外部
// 这里的 -> auto 自动推导在c++11不支持,c++14中对auto进行了扩展
thread t1([&] () -> auto {
i = 100;
cout << "线程:" << i << endl;
});
_sleep(10);
cout << i << endl;
捕获形式 说明
[] 不捕获任何外部变量
[i, …] 以值得形式捕获指定的多个外部变量(用逗号分隔);如果引用捕获,需要显示声明&
[this] 以值的形式捕获this指针
[=] 以值的形式捕获所有外部变量
[&] 以引用形式捕获所有外部变量
[=, &x] 变量x以引用形式捕获,其余变量以传值形式捕获
[&, x] 变量x以值的形式捕获,其余变量以引用形式捕获