目录
1. 初始化列表
#include <iostream>
#include <list>
#include <vector>
using namespace std;
int main()
{
auto i = { 1, 2, 3 };
cout << typeid(i).name() << endl; // class std::initializer_list<int>
int a = 10;
int b{ 10 }; // 一切变量皆可用 {} 赋值,默认变量不建议这样用
cout << a << "," << b << endl;
vector<int> arr1 = { 1, 2, 3, 4, 5 };
vector<int> arr2{ 1, 2, 3, 4, 5 }; // vector、list都可以用初始化列表赋值
for (auto e : arr1)
{
cout << e << ' ';
}
cout << endl;
for (auto e : arr2)
{
cout << e << ' ';
}
cout << endl;
struct Point
{
int _x, _y, _z;
};
list<Point> ls1 = { {1, 2, 3}, {3, 3, 3}, {3, 6, 9} };
for (auto& e : ls1)
{
cout << e._x << ", " << e._y << ", " << e._z << endl;
}
cout << endl;
}
2. 右值引用
左值引用与右值引用:
#include <iostream>
#include <list>
#include <vector>
using namespace std;
int main()
{
int num = 10;
int& a = num; // 左值引用
const int& a0 = 10; // 常量左值引用可以操作右值
cout << "a0: " << a0 << endl;
int&& a1 = 10;
cout << "a1: " << a1 << endl;
a1 = 100;
cout << "a1:" << a1 << endl;
const int&& a2 = 1000;
cout << "a2: " << a2 << endl;
// 常量右值引用,在实际应用场景中很少出现
// 一方面,右值引用主要用于移动语义和完美转发,前者需要有修改右值的权限
// 另一方面,常量右值引用的作用就是引用一个不可修改的右值,这项工作完全可以由常量左值引用实现
return 0;
}
转移语义:构造时有拷贝构造和移动构造两种策略,转移构造通过转移语义就是将原变量赋给新变量,而不做拷贝,这样原变量销毁,但是原变量的数据没有销毁,提高了效率。当编译器识别到构造函数的参数是纯右值或者将亡值时,会采用移动构造策略。
完美转发:std::forward() 函数将保持变量类型的属性
#include <iostream>
#include <list>
#include <vector>
using namespace std;
vector<int> test()
{
vector<int> tmp = { 1, 2, 3, 4 };
return tmp;
}
void reference(string& str)
{
cout << "左值" << endl;
}
void reference(string&& str)
{
cout << "右值" << endl;
}
// 完美转发
template<typename T>
void perfect_forward(T&& t)
{
// 完美茶转发,保持他的属性
reference(t);
//reference(std::forward<T>(t));
}
int main()
{
vector<int> v = test();
for (auto& e : v)
{
cout << e << ' ';
}
cout << endl << endl;
// test 函数的返回值是一个将亡值:即将被销毁,却能够被移动的值。
// 要拿到一个将亡值,就需要用到右值引用:T&&,通过移动构造,减少拷贝次数
string lv1 = "test_str"; // 这是一个左值
string&& rv1 = move(lv1); // std::move 可以将左值转移为右值
reference(lv1); // 左值
cout << "lv1: " << lv1 << endl;
perfect_forward(lv1); // 左值
reference(rv1); // 左值
cout << "rv1: " << rv1 << endl;
perfect_forward(rv1); // 左值
// rv1 虽然引用了一个右值,但由于它是一个引用,所以它是一个左值
reference("str"); // 右值
perfect_forward("str"); // 右值
return 0;
}
移动构造、移动赋值:当类没有实现移动构造,且没有实现析构函数、拷贝构造、拷贝赋值重载中的任意一个,编译器才会默认生成一个移动构造。
3. 拷贝禁用
delete 关键字不止用于空间的释放,还用于类的拷贝禁用
#include <iostream>
using namespace std;
template<class T>
class Test
{
public:
Test()
{}
Test(const Test& t) = delete;
// 防止从内部和外部进行拷贝构造,应用于单例模式和智能指针
void func()
{
Test<T> tmp(*this);
}
private:
T p[10];
};
int main()
{
Test<int> t1;
//Test<int> t2(t1);
//t1.func();
// 从内部和外部拷贝都会报错:尝试引用已删除的函数
return 0;
}
4. lambda表达式
[capture-list] (parameters)mustable -> return-type {statement}
#include <iostream>
using namespace std;
int main()
{
// 用lambda表达式比较int数据
auto compare = [](int x, int y) {return x > y; };
//auto compare = [](int x, int y) -> bool{return x > y; };
// [capture-lest]: 捕捉列表,在lambda函数开始处,编译器根据 [] 判断接下来代码是否为lambda函数函数
// (parameters): 参数列表,如无参数可省略
// -> returntype: 返回值类型,可省略,由编译器进行返回值类型推导
// {statement}: 函数体
// lambda 本质是一个可调用的对象,相比于仿函数写法更简洁可读性更高
cout << compare(10, 20) << endl;
auto add = [](int x, int y) {return x + y; };
cout << add(10, 20) << endl;
int a = 100;
auto sub = [a](int x) { return a - x; };
cout << sub(50) << endl;
int b = 1000;
//auto swap1 = [&a, &b]()mutable // 传值捕捉,生成临时变量
auto swap1 = [&a, &b]()mutable // 传引用捕捉
{
int tmp = a;
a = b;
b = tmp;
};
// 捕捉列表捕捉的数据带const属性
// 加上 mutable 之后捕捉列表的数据就可以改变了
swap1();
cout << "a=" << a << ", b=" << b << endl; // a=1000, b=100
//auto swap2 = [=]()mutable // 传值捕捉所有变量
auto swap2 = [&]()mutable // 传引用捕捉所有变量
{
int tmp = a;
a = b;
b = tmp;
};
// 捕捉列表捕捉的数据带const属性
// 加上 mutable 之后捕捉列表的数据就可以改变了
swap2();
cout << "a=" << a << ", b=" << b << endl; // a=100, b=1000
int x = 200;
auto swap3 = [=, &a, &b]()mutable // 混合捕捉
{
a = x;
b = x;
x = a + b;
};
// 捕捉列表捕捉的数据带const属性
// 加上 mutable 之后捕捉列表的数据就可以改变了
swap3();
cout << "a=" << a << ", b=" << b << ", x=" << x << endl; // a=200, b=200, x=200
return 0;
}
#include <iostream>
#include <thread>
#include <vector>
#include <Windows.h>
using namespace std;
int main()
{
vector<thread> vThread;
vThread.resize(5);
int i = 0;
int x = 0;
for (auto& t : vThread)
{
t = thread([&i, x]()
{
while (i < 20)
{
cout << "thread-" << x << " -> " << i << endl;
Sleep(1000);
++i;
}
});
++x;
}
for (auto& t : vThread)
{
t.join();
}
return 0;
}
5. 可变参数模板
#include <iostream>
using namespace std;
void ShowList()
{
cout << endl;
}
// Args 是一个模板参数包
template<class T, class ...Args>
void ShowList(T val, Args... args)
{
// 解析参数包
cout << val << " ";
ShowList(args...);
}
int main()
{
ShowList(1);
ShowList(1, 1.0);
ShowList(1, 1.0, string("hello"));
ShowList();
return 0;
}
6. 包装器
#include <iostream>
#include <functional>
using namespace std;
int func(int a, int b)
{
return a + b;
}
struct Func
{
int operator()(int a, int b)
{
return a + b;
}
};
class Plus
{
public:
static int plusi(int a, int b)
{
return a + b;
}
int plusd(int a, int b)
{
return a + b;
}
};
int main()
{
function<int(int, int)> f1;
f1 = func;
cout << f1(1, 1) << endl;
function<int(int, int)> f2(func);
cout << f2(2, 2) << endl;
function<int(int, int)> f3 = Func();
cout << f3(3, 3) << endl;
function<int(int, int)> f4 = [](int a, int b) {return a + b; };
cout << f4(4, 4) << endl;
function<int(int, int)> f5 = Plus::plusi; // 类静态成员函数指针
cout << f5(5, 5) << endl;
function<int(Plus, int, int)> f6 = &Plus::plusd; // 类成员函数指针
cout << f6(Plus(), 6, 6) << endl;
Plus plus;
function<int(Plus, int, int)> f7 = &Plus::plusd;
cout << f7(plus, 7, 7) << endl;
function<int(int, int)> f8 = [&plus](int a, int b)->int {return plus.plusd(a, b); };
cout << f8(8, 8) << endl;
return 0;
}