目录
1.可变模版参数
[1.1 基本语法](#1.1 基本语法)
编辑
[1.2 包扩展](#1.2 包扩展)
[2. lambda](#2. lambda)
[2.1 基本语法](#2.1 基本语法)
[2.2 应用场景](#2.2 应用场景)
3.包装器
[3.1 function](#3.1 function)
[3.2 bind](#3.2 bind)
[4. 新的类功能](#4. 新的类功能)
[4.1 默认移动构造和移动赋值](#4.1 默认移动构造和移动赋值)
[4.2 delete和default](#4.2 delete和default)
[5. 智能指针](#5. 智能指针)
[5.1 unique_ptr](#5.1 unique_ptr)
[5.2 shared_ptr](#5.2 shared_ptr)
[5.3 weak_ptr](#5.3 weak_ptr)
1.可变模版参数
1.1 基本语法
可变模板参数是C++11引入的强大特性,允许模板接受任意数量和类型的参数。其基本语法使用省略号(...)表示参数包
template<class ...Args> void Func(Args... args) {}
template<class ...Args> void Func(Args&... args) {}
template<class ...Args> void Func(Args&&... args) {}
这里的Args是模板参数包,args是函数参数包,可以包含零个或多个参数。
我们可以用sizeof...来计算参数包中的参数个数
cpp
复制代码
template <class ...Args>
void Print(Args&&... args)
{
cout << sizeof...(args) << endl;
}
int main()
{
double x = 2.2;
Print(); // 0个参数
Print(1); // 1个参数
Print(1, string("aaaaa")); // 2个参数
Print(1.1, string("bbbbbb"), x); //3个参数
return 0;
}

1.2 包扩展
参数包本身不能直接使用,需要通过包扩展来展开。常见的扩展方法就是递归推导
2. lambda
Lambda表达式是C++11引入的一种定义匿名函数对象的简洁方式。它允许我们在需要函数的地方直接内联定义函数,而无需单独声明命名函数。
2.1 基本语法
捕获变量 \](参数)-\> 返回类型 {函数体}
捕获列表有以下几种形式:
\] 不捕获任何变量
\[=\] 以值方式捕获所有外部变量
\[\&\] 以引用方式捕获所有外部变量
\[a, \&b\] 混合捕获方式
#### 2.2 应用场景
Lambda表达式特别适用于:一次性使用的函数对象
```cpp
// 在STL算法中使用lambda
std::vector nums = {1, 2, 3, 4, 5};
std::for_each(nums.begin(), nums.end(), [](int n) {
std::cout << n * 2 << " ";
});
```
### 3.包装器
#### 3.1 function
std::function 是一个通用的函数包装器,可以存储、复制和调用任何可调用对象
> function\<返回类型(参数类型)\> 包装器名称 = 被包装函数对象
```cpp
#include
std::function adder = [](int a, int b) { return a + b; };
int result = adder(2, 3); // 结果为5
```
#### 3.2 bind
std::bind 用于部分应用函数,可以绑定参数、重排参数顺序
```cpp
#include
#include
using namespace std;
using placeholders::_1;
using placeholders::_2;
using placeholders::_3;
int Sub(int a, int b)
{
return a-b;
}
int main()
{
// bind 本质返回的是一个仿函数对象
// 调整参数顺序
// _1代表第一个实参
// _2代表第二个实参
// ...
auto sub1 = bind(Sub, _1, _2);
cout << sub1(10, 5) << endl;//结果是5
//调整参数顺序
auto sub2 = bind(Sub, _2, _1);
cout << sub2(10, 5) << endl;//结果是-5
//绑定第一个参数是20
auto sub3 = bind(Sub, 20, _1);
cout << sub3(10, 5) << endl;//结果是10
return 0;
}
```
### 4. 新的类功能
#### 4.1 默认移动构造和移动赋值
前面我们已经学过了C++类中,有6个默认成员函数:构造函数/析构函数/拷贝构造函数/拷贝赋值重载/取地址重载/const取地址重载。我们用的最多的是前四个,这些函数都是我们在类中不写编译器会自动生成的。C++11新增了两个默认成员函数,就是移动构造函数和移动赋值重载。
如果你没有实现移动构造,且没有实现析构、拷贝构造、拷贝赋值中的任意一个。那么编译器会自动生成一个默认移动构造;
如果你没有实现移动赋值重载函数,且没有实现析构函数、拷贝构造、拷贝赋值重载中的任意一个,那么编译器会自动生成一个默认移动赋值。
默认生成的移动构造/移动赋值重载,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。
如果你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值。
#### 4.2 delete和default
函数声明 = default:显式要求编译器生成默认版本的函数
函数声明 = delete:禁止使用某些函数
### 5. 智能指针
C++98设计的一个智能指针叫 auto_ptr ,它的特点是在拷贝时把被拷贝对象的资源管理权交给拷贝对象,但这样可能会使被拷贝对象悬空,从而报错。这是一个不太好的智能指针,不建议使用。
C++11之后引入了三种智能指针,用于自动管理动态分配的内存:
#### 5.1 unique_ptr
unique_ptr 正如它的名字所说,它的特点就是具有唯一性,不支持拷贝,只支持移动。
#### 5.2 shared_ptr
shared_ptr 的特点是支持拷贝,也支持移动,共享资源的管理,使用引用计数方式实现
#### 5.3 weak_ptr
weak_ptr 不支持RAII,也就是说它不能直接管理资源,其产生的本质是解决shared_ptr的循环引用导致内存泄漏的问题。
```cpp
#include
#include
using namespace std;
int main()
{
auto_ptr ap1(new int(3));
auto_ptr ap2(ap1);//此时ap1悬空
unique_ptr up1(new int(5));
unique_ptr up2(move(up1));//可以移动,但此时up1已经悬空,要注意
//unique_ptr up3(up1);//不支持拷贝,会报错
shared_ptr sp1(new int(10));
shared_ptr sp2(move(sp1));//支持移动,但sp1也悬空了
shared_ptr sp3(sp2);//也支持拷贝
return 0;
}
```

这里我们可以看到被移动后的指针都悬空了,所以在移动时一定要小心!
```cpp
//weak_ptr使用场景
#include
#include
class B; // 前向声明
class A {
public:
std::shared_ptr b_ptr;
~A() { std::cout << "A destroyed\n"; }
};
class B {
public:
std::shared_ptr a_ptr; // 这里会造成循环引用!
~B() { std::cout << "B destroyed\n"; }
};
class C {
public:
std::weak_ptr a_ptr; // 使用 weak_ptr 打破循环引用
~C() { std::cout << "C destroyed\n"; }
};
void testCycle() {
auto a = std::make_shared();
auto b = std::make_shared();
a->b_ptr = b;
b->a_ptr = a; // 循环引用!内存泄漏!
std::cout << "A use count: " << a.use_count() << std::endl; // 2
std::cout << "B use count: " << b.use_count() << std::endl; // 2
} // a 和 b 的引用计数永远不为0,无法释放!
void testNoCycle() {
auto a = std::make_shared();
auto c = std::make_shared();
c->a_ptr = a; // weak_ptr 不增加引用计数
std::cout << "A use count: " << a.use_count() << std::endl; // 1
} // 正常释放
int main()
{
testCycle();
testNoCycle();
return 0;
}
```