目录
[1. C++11 简介](#1. C++11 简介)
[为什么会有 C++11?](#为什么会有 C++11?)
[2. 统一列表初始化:{} 初始化直接完成](#2. 统一列表初始化:{} 初始化直接完成)
[2.1 基础 {} 初始化语法](#2.1 基础 {} 初始化语法)
[2.2 std::initializer_list 容器初始化](#2.2 std::initializer_list 容器初始化)
[2.3 自定义类支持 {} 初始化](#2.3 自定义类支持 {} 初始化)
[3. 变量类型推导:auto/decltype/nullptr 解放手写类型](#3. 变量类型推导:auto/decltype/nullptr 解放手写类型)
[3.1 auto:自动类型推导(最常用)](#3.1 auto:自动类型推导(最常用))
[3.2 decltype:表达式类型推导](#3.2 decltype:表达式类型推导)
[3.3 nullptr:安全的空指针](#3.3 nullptr:安全的空指针)
[4. 范围 for 循环:极简容器遍历语法](#4. 范围 for 循环:极简容器遍历语法)
[5. final 与 override:继承多态的安全防护](#5. final 与 override:继承多态的安全防护)
[5.1 final:禁止继承 / 重写](#5.1 final:禁止继承 / 重写)
[6. 智能指针:自动化内存管理,杜绝内存泄漏](#6. 智能指针:自动化内存管理,杜绝内存泄漏)
[7. C++11 新容器:更高效、更实用的 STL 组件](#7. C++11 新容器:更高效、更实用的 STL 组件)
[7.2 forward_list:单向链表](#7.2 forward_list:单向链表)
[8. 右值引用与移动语义:C++11 最核心的性能革命](#8. 右值引用与移动语义:C++11 最核心的性能革命)
[8.1 左值与右值](#8.1 左值与右值)
[9. Lambda 表达式:就地匿名函数,简化回调逻辑](#9. Lambda 表达式:就地匿名函数,简化回调逻辑)
[9.1 Lambda 基础语法](#9.1 Lambda 基础语法)
[9.2 Lambda 实战:排序自定义类型](#9.2 Lambda 实战:排序自定义类型)
[10. 包装器 function 与 bind:统一可调用对象](#10. 包装器 function 与 bind:统一可调用对象)
[10.1 function:包装可调用对象](#10.1 function:包装可调用对象)
[10.2 bind:绑定参数 / 调整顺序](#10.2 bind:绑定参数 / 调整顺序)
[11. C++11 线程库:跨平台多线程编程](#11. C++11 线程库:跨平台多线程编程)
[11.1 基础线程创建](#11.1 基础线程创建)
[12.2 原子操作 atomic:无锁线程安全](#12.2 原子操作 atomic:无锁线程安全)
[12.3 lock_guard:RAII 互斥锁](#12.3 lock_guard:RAII 互斥锁)
1. C++11 简介
为什么会有 C++11?
在 C++11 之前,工业界长期使用C++98/03 标准。其中 C++98 是 C++ 第一版正式标准,C++03 仅对 C++98 做了漏洞修复,核心语法无任何改动。这就导致 C++ 在近 10 年时间里,语法繁琐、效率受限、内存安全差、缺乏原生并发支持,逐渐被 Java、Python 等语言挤压生存空间。
C++ 标准委员会原本计划 2007 年发布新版本,命名为 C++07,后因技术难度一再延期,更名为 C++0x(x 代表未知年份),最终在2011 年正式定稿,得名 C++11。
特点:
- 语法更简洁:减少冗余代码,提升开发效率
- 效率更高:右值引用、移动语义大幅降低拷贝开销
- 内存更安全:智能指针、nullptr 杜绝空指针与内存泄漏
- 功能更强大:原生线程库、哈希容器、Lambda 表达式适配现代开发
- 兼容性更好:完全兼容 C++98/03,平滑升级无压力
2. 统一列表初始化:{} 初始化直接完成
在 C++98 中,花括号{}仅能用于数组、结构体的初始化,自定义类型、动态内存都无法使用,初始化语法混乱。C++11 提出统一列表初始化 ,让{}成为所有类型的通用初始化方式,彻底统一初始化语法。
2.1 基础 {} 初始化语法
C++11 中,内置类型、自定义类型、数组、动态内存都能使用{}初始化,等号=可写可不写。
cpp
#include <iostream>
using namespace std;
struct Point {
int _x;
int _y;
};
class Date {
public:
Date(int year, int month, int day)
: _year(year), _month(month), _day(day) {}
void Print() const {
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
private:
int _year;
int _month;
int _day;
};
int main() {
int a{10}; // 等价于 int a = 10;
double b{3.14}; // 等价于 double b = 3.14;
cout << "内置类型初始化:a = " << a << ",b = " << b << endl;
int arr1[]{1, 2, 3, 4, 5};
int arr2[5]{0}; // 全部初始化为0
cout << "数组初始化:";
for (int i = 0; i < 5; ++i) {
cout << arr1[i] << " ";
}
cout << endl;
Point p{10, 20};
cout << "结构体初始化:x = " << p._x << ",y = " << p._y << endl;
// 4. 类对象初始化(调用构造函数)
Date d1{2026, 4, 23};
Date d2 = {2026, 1, 1};
cout << "类对象初始化:";
d1.Print();
d2.Print();
int* pa = new int[4]{1, 2, 3, 4};
cout << "动态数组初始化:";
for (int i = 0; i < 4; ++i) {
cout << pa[i] << " ";
}
cout << endl;
delete[] pa;
return 0;
}
2.2 std::initializer_list 容器初始化
C++11 为 STL 容器新增了std::initializer_list 类型的构造函数与赋值运算符,容器可以直接用{}批量初始化、赋值,无需逐个 push_back。、
cpp
#include <iostream>
#include <vector>
#include <list>
#include <map>
using namespace std;
int main() {
// 1. vector初始化
vector<int> v = {1, 2, 3, 4, 5};
cout << "vector初始化:";
for (auto x : v) {
cout << x << " ";
}
cout << endl;
// 2. list初始化
list<int> lt{10, 20, 30};
cout << "list初始化:";
for (auto x : lt) {
cout << x << " ";
}
cout << endl;
// 3. map初始化(键值对)
map<string, string> dict = {
{"insert", "插入"},
{"delete", "删除"},
{"update", "更新"}
};
cout << "map初始化:" << endl;
for (auto& kv : dict) {
cout << kv.first << " : " << kv.second << endl;
}
// 4. 容器赋值
v = {100, 200, 300};
cout << "vector赋值后:";
for (auto x : v) {
cout << x << " ";
}
cout << endl;
return 0;
}
2.3 自定义类支持 {} 初始化
如果想让自己写的类支持{}初始化,只需添加std::initializer_list作为参数的构造函数即可。
这里我们自定义一个MyVector来演试一下
cpp
#include <iostream>
#include <initializer_list>
using namespace std;
// 自定义vector,支持{}初始化
template<class T>
class MyVector {
public:
// 构造函数:支持initializer_list
MyVector(initializer_list<T> list) {
_size = list.size();
_data = new T[_size];
int index = 0;
for (auto& x : list) {
_data[index++] = x;
}
}
// 析构函数
~MyVector() {
delete[] _data;
}
// 打印数据
void Print() const {
for (int i = 0; i < _size; ++i) {
cout << _data[i] << " ";
}
cout << endl;
}
private:
T* _data;
int _size;
};
int main() {
// 自定义类使用{}初始化
MyVector<int> mv{1, 2, 3, 4, 5};
cout << "自定义vector初始化:";
mv.Print();
return 0;
}
这样即使是自定义的类,也可以使用{}了
3. 变量类型推导:auto/decltype/nullptr 解放手写类型
C++98 中,变量必须显式声明类型,遇到迭代器、函数指针等超长类型名时,代码极其繁琐。C++11 推出类型推导特性,让编译器自动推算变量类型,大幅简化代码。
3.1 auto:自动类型推导(最常用)
C++11 废弃了 auto 原本的 "自动存储类型" 含义,将其改为自动类型推导,编译器会根据变量的初始化值,自动推算变量类型。
核心规则 :auto 定义的变量必须初始化,否则编译器无法推导类型。下面我们举一个例子来直观地看一下
cpp
#include <iostream>
#include <map>
#include <cstring>
using namespace std;
int main() {
int a = 10;
auto pa = &a;
auto pf = strcpy;
cout << "pa的类型:" << typeid(pa).name() << endl;
cout << "pf的类型:" << typeid(pf).name() << endl;
map<string, string> dict = {{"name", "张三"}, {"age", "20"}};
// map<string, string>::iterator it = dict.begin();
// C++11写法:auto一键推导
auto it = dict.begin();
cout << "迭代器遍历:" << it->first << " : " << it->second << endl;
auto sum = a + 3.14; // 推导为 double
cout << "sum的类型:" << typeid(sum).name() << ",值 = " << sum << endl;
return 0;
}
3.2 decltype:表达式类型推导
auto 用于推导变量 的类型,而decltype 用于推导表达式的类型,不会实际执行表达式,常用于模板编程、类型获取场景。
cpp
#include <iostream>
using namespace std;
template<class T1, class T2>
void GetType(T1 t1, T2 t2) {
// 推导t1*t2的类型
decltype(t1 * t2) ret;
cout << "t1*t2的类型:" << typeid(ret).name() << endl;
}
int main() {
const int x = 1;
double y = 2.2;
decltype(x * y) ret; // 推导为 double
decltype(&x) p = &x; // 推导为 const int*
cout << "ret的类型:" << typeid(ret).name() << endl;
cout << "p的类型:" << typeid(p).name() << endl;
GetType(10, 3.14); // int * double → double
GetType('a', 100); // char * int → int
return 0;
}
3.3 nullptr:安全的空指针
C++98 中,NULL 本质是宏定义的0,既是整数又是空指针,极易引发函数重载歧义。C++11 推出nullptr,专门表示空指针,类型安全,无歧义。
4. 范围 for 循环:极简容器遍历语法
C++98 中遍历容器需要手写迭代器或下标,代码繁琐。C++11 推出范围 for 循环,无需关心迭代器、下标,直接遍历容器内所有元素,语法极简。
核心语法 :for (auto 变量 : 容器) { 循环体 }
这了我们依旧来句一个例子
cpp
#include <iostream>
#include <vector>
#include <list>
using namespace std;
int main() {
// 1. vector遍历
vector<int> v = {1, 2, 3, 4, 5};
cout << "vector遍历:";
for (auto x : v) {
cout << x << " ";
}
cout << endl;
// 2. list遍历
list<string> lt{"hello", "c++", "11"};
cout << "list遍历:";
for (auto& s : lt) {
cout << s << " ";
}
cout << endl;
// 3. 数组遍历
int arr[]{10, 20, 30};
cout << "数组遍历:";
for (auto x : arr) {
cout << x << " ";
}
cout << endl;
return 0;
}
5. final 与 override:继承多态的安全防护
在 C++ 继承与多态中,经常出现意外继承、虚函数重写写错签名 等问题,导致程序逻辑错误。C++11 推出final 和override关键字,专门解决这些问题,提升代码安全性。
5.1 final:禁止继承 / 重写
final 有两个作用:
- 修饰类:该类无法被继承
- 修饰虚函数:该虚函数无法被子类重写
cpp
#include <iostream>
using namespace std;
// 1. final修饰类:禁止被继承
class Base final {
public:
virtual void Show() {
cout << "Base::Show" << endl;
}
};
// 报错:Base被final修饰,无法被继承
// class Derive : public Base {};
// 2. final修饰虚函数:禁止重写
class A {
public:
virtual void Func() final {
cout << "A::Func(禁止重写)" << endl;
}
};
class B : public A {
public:
// 报错:Func被final修饰,无法重写
// void Func() override {}
};
int main() {
B b;
b.Func();
return 0;
}
6. 智能指针:自动化内存管理,杜绝内存泄漏
C++ 最经典的问题就是内存泄漏 ------ 手动 new/delete 容易忘记释放、重复释放、野指针等问题。C++11 推出智能指针,利用 RAII(资源获取即初始化)机制,自动管理内存,无需手动 delete。
C++11 核心智能指针:
- unique_ptr:独占式智能指针,同一时间只有一个指针管理对象
- shared_ptr:共享式智能指针,引用计数管理,计数为 0 自动释放
- weak_ptr:辅助 shared_ptr,解决循环引用问题
cpp
#include <iostream>
#include <memory>
using namespace std;
int main() {
// 1. 定义unique_ptr
unique_ptr<int> up1 = make_unique<int>(10);
cout << "up1指向的值:" << *up1 << endl;
// 2. 独占式:不能拷贝,只能移动
// unique_ptr<int> up2 = up1; // 报错:不能拷贝
unique_ptr<int> up2 = move(up1); // 移动所有权
if (!up1) {
cout << "up1已空,所有权转移给up2" << endl;
}
cout << "up2指向的值:" << *up2 << endl;
// 3. 管理自定义对象
unique_ptr<string> up3 = make_unique<string>("hello c++11");
cout << "字符串:" << *up3 << endl;
// 无需手动delete,出作用域自动释放
return 0;
}
7. C++11 新容器:更高效、更实用的 STL 组件
C++11 在原有 STL 容器基础上,新增array、forward_list、unordered_map、unordered_set 等容器,其中unordered 系列(哈希容器) 是工程开发中最常用的高效容器。
array:静态数组(安全版普通数组)
array 是固定大小的静态数组,相比普通数组,支持边界检查、迭代器、STL 接口,更安全。
cpp
#include <iostream>
#include <array>
using namespace std;
int main() {
// 定义array:类型 + 大小
array<int, 5> arr = {1, 2, 3, 4, 5};
cout << "array遍历:";
for (auto x : arr) {
cout << x << " ";
}
cout << endl;
// 常用接口
cout << "数组大小:" << arr.size() << endl;
cout << "第一个元素:" << arr.front() << endl;
cout << "最后一个元素:" << arr.back() << endl;
cout << "数组是否为空:" << boolalpha << arr.empty() << endl;
return 0;
}
7.2 forward_list:单向链表
forward_list 是单向链表,相比 list(双向链表),占用内存更少,仅支持正向遍历,适合内存敏感场景。
cpp
#include <iostream>
#include <forward_list>
using namespace std;
int main() {
forward_list<int> fl{1, 2, 3, 4};
cout << "forward_list遍历:";
for (auto x : fl) {
cout << x << " ";
}
cout << endl;
// 头部插入
fl.push_front(0);
cout << "头部插入后:";
for (auto x : fl) {
cout << x << " ";
}
cout << endl;
return 0;
}
8. 右值引用与移动语义:C++11 最核心的性能革命
右值引用是 C++11最核心、最难、最重要 的特性,解决了临时对象拷贝开销大 的问题,通过移动语义实现 "资源转移",而非 "资源拷贝",大幅提升程序性能。
8.1 左值与右值
- 左值:可以取地址、可以放在等号左边的表达式(变量、指针解引用)
- 右值:临时值,不能取地址、不能放在等号左边(字面量、表达式返回值、函数临时返回值)
引用写法:
- 左值引用:
int& - 右值引用:
int&&
这里我们用一段例子来看一下
cpp
#include <iostream>
using namespace std;
int main() {
int a = 10;
// 左值:能取地址
int& ra = a;
cout << "左值引用:ra = " << ra << endl;
// 右值:临时值,不能取地址
int&& rr = 10;
// 右值引用可以修改
rr = 20;
cout << "右值引用:rr = " << rr << endl;
return 0;
}
9. Lambda 表达式:就地匿名函数,简化回调逻辑
C++98 中,编写排序、查找等回调函数需要定义仿函数类,代码繁琐。C++11 推出Lambda 表达式,是就地定义的匿名函数,无需定义类,语法简洁,适合临时回调场景。
9.1 Lambda 基础语法
[捕获列表] (参数列表) mutable -> 返回值 { 函数体 }
- 捕获列表:获取外部变量
- 参数列表:和普通函数一致
- mutable:取消常量属性
- 返回值:可省略,编译器自动推导
9.2 Lambda 实战:排序自定义类型
cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 商品结构体
struct Goods {
string _name;
double _price;
int _score;
};
int main() {
vector<Goods> v = {
{"苹果", 2.1, 5},
{"香蕉", 3.0, 4},
{"橙子", 1.5, 3},
{"葡萄", 4.0, 5}
};
// 1. 按价格升序
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
return g1._price < g2._price;
});
cout << "按价格升序:" << endl;
for (auto& g : v) {
cout << g._name << " : " << g._price << endl;
}
// 2. 按评分降序
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
return g1._score > g2._score;
});
cout << "按评分降序:" << endl;
for (auto& g : v) {
cout << g._name << " : " << g._score << endl;
}
return 0;
}
10. 包装器 function 与 bind:统一可调用对象
C++ 中有多种可调用对象:普通函数、函数指针、仿函数、Lambda 表达式,类型不统一,模板中会多次实例化。C++11 推出function 和bind,统一包装所有可调用对象,适配各种场景。
10.1 function:包装可调用对象
function 是可调用对象包装器,能包装普通函数、仿函数、Lambda、成员函数,统一类型。
cpp
#include <iostream>
#include <functional>
using namespace std;
// 普通函数
int Add(int a, int b) {
return a + b;
}
// 仿函数
struct Sub {
int operator()(int a, int b) {
return a - b;
}
};
int main() {
// 1. 包装普通函数
function<int(int, int)> f1 = Add;
cout << "1+2=" << f1(1, 2) << endl;
// 2. 包装仿函数
function<int(int, int)> f2 = Sub();
cout << "3-1=" << f2(3, 1) << endl;
// 3. 包装Lambda
function<int(int, int)> f3 = [](int a, int b) {
return a * b;
};
cout << "2*3=" << f3(2, 3) << endl;
return 0;
}
10.2 bind:绑定参数 / 调整顺序
bind 用于绑定函数参数、调整参数顺序,生成新的可调用对象。
cpp
#include <iostream>
#include <functional>
using namespace std;
int Func(int a, int b, int c) {
return a + b + c;
}
int main() {
// 1. 绑定固定参数
auto f1 = bind(Func, 10, 20, placeholders::_1);
cout << "绑定后:" << f1(30) << endl; // 10+20+30=60
// 2. 调整参数顺序
auto f2 = bind(Func, placeholders::_3, placeholders::_1, placeholders::_2);
cout << "调整顺序:" << f2(1, 2, 3) << endl; // 3+1+2=6
return 0;
}
11. C++11 线程库:跨平台多线程编程
C++98 无原生线程库,多线程依赖平台 API(Windows CreateThread、Linux pthread),代码不可移植。C++11 推出原生线程库,跨平台、简洁易用,支持线程、互斥锁、原子操作、条件变量。
11.1 基础线程创建
cpp
#include <iostream>
#include <thread>
using namespace std;
// 线程函数
void ThreadFunc(int x) {
cout << "线程运行,参数:" << x << endl;
}
int main() {
// 1. 线程函数+参数
thread t1(ThreadFunc, 10);
// 2. Lambda线程
thread t2([]{
cout << "Lambda线程运行" << endl;
});
// 等待线程结束
t1.join();
t2.join();
cout << "主线程结束" << endl;
return 0;
}
12.2 原子操作 atomic:无锁线程安全
多线程修改共享变量会引发数据竞争,C++11 推出atomic原子类型,无锁、线程安全,效率远高于互斥锁。
cpp
#include <iostream>
#include <thread>
#include <atomic>
using namespace std;
// 原子整数,线程安全
atomic<int> sum{0};
// 线程函数:累加
void AddSum(int n) {
for (int i = 0; i < n; ++i) {
sum++;
}
}
int main() {
// 两个线程累加100万次
thread t1(AddSum, 1000000);
thread t2(AddSum, 1000000);
t1.join();
t2.join();
// 结果正确:2000000
cout << "sum = " << sum << endl;
return 0;
}
12.3 lock_guard:RAII 互斥锁
lock_guard 利用 RAII 机制,构造上锁、析构解锁,避免忘记 unlock 导致死锁。
cpp
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx;
int count{0};
// 线程函数:加锁累加
void AddCount() {
for (int i = 0; i < 1000; ++i) {
// 自动上锁
lock_guard<mutex> lock(mtx);
count++;
// 自动解锁
}
}
int main() {
thread t1(AddCount);
thread t2(AddCount);
t1.join();
t2.join();
cout << "count = " << count << endl;
return 0;
}