C++基础:C++11部分内容

1 C++11 发展历史

1.1 版本基础信息

解释:C++98是最早标准,C++11是改动最大的一次升级,原本计划2010年前发布,代号C++0x,2011年正式定稿。C++03到C++11间隔8年,之后标准固定每3年更新一次

1.2 C++11 新增核心大类功能

统一初始化、auto/decltype自动类型推导、lambda匿名函数、constexpr编译期常量、右值引用&移动语义、可变参数模板、智能指针、多线程、正则、全新类语法、STL容器拓展、函数包装器function/bind。

2 列表初始化(统一初始化 {}

2.1 C++98 旧版{}限制

解释:老标准只有数组、结构体能用{}初始化,普通类不能用,初始化方式不统一。

示例:

cpp 复制代码
#include <iostream>
using namespace std;
struct Point { int x, y; };
int main()
{
    int arr[5] = {1,2,3,4,5}; // 数组支持
    Point p = {10,20};         // 结构体支持
    return 0;
}

2.2 C++11 统一列表初始化

2.2.1 核心规则

解释:所有类型(内置/类/引用)都能用{}初始化 ,等号=可以省略;编译器会自动构造临时对象,并且优化掉拷贝,效率更高。

2.2.2 完整示例
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

class Date
{
public:
    Date(int y=1, int m=1, int d=1)
    {
        cout << "构造函数执行" << endl;
    }
    Date(const Date&) { cout << "拷贝构造执行" << endl; }
};

int main()
{
    // 1.内置类型,可省略=
    int a{10};
    int b = {20};

    // 2.自定义类两种写法
    Date d1{2026,8,7};
    Date d2 = {2026,1,1};

    // 3.const引用绑定临时对象
    const Date& ref{2025,12,1};

    // 4.容器传参简化,不用写Date(xxx)
    vector<Date> v;
    v.push_back({2024,5,6}); 

    return 0;
}

运行说明:不会打印拷贝构造,编译器直接优化构造,没有临时对象拷贝。

2.3 std::initializer_list

2.3.1 通俗解释

{1,2,3,4} 这种多值列表底层会转成initializer_list,内部存一个数组+首尾指针,STL容器全部加了对应构造函数,支持一次性批量初始化容器。

2.3.2 示例
cpp 复制代码
#include <iostream>
#include <vector>
#include <map>
using namespace std;

int main()
{
    // vector直接批量初始化
    vector<int> v = {1,2,3,4,5};
    vector<int> v2({10,20,30});

    // map批量键值对初始化
    map<string, int> mp = {{"苹果",5},{"香蕉",3}};

    // 列表赋值
    v = {100,200,300};
    return 0;
}

3 右值引用与移动语义(解决深拷贝效率问题)

3.1 左值、右值区分(初学者必懂)

3.1.1 左值

解释:有名字、能取地址,能放在=左边。变量、解引用指针、数组元素都是左值。

3.1.2 右值

解释:没有持久内存、不能取地址,只能放在=右边。数字字面量、表达式结果、函数返回临时对象都是右值。

示例:

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;
int main()
{
    int a = 10;
    // a是左值,可以取地址
    cout << &a << endl;

    // 10、a+20、string("test")都是右值,不能取地址
    // cout << &10; 报错
    // cout << &(a+20); 报错
    // cout << &string("test"); 报错
    return 0;
}

3.2 左值引用T&、右值引用T&&

3.2.1 基础规则
  1. T&左值引用:只能绑定左值;const T&可以绑定左值+右值
  2. T&&右值引用:只能绑定右值;左值想要绑定必须用std::move(变量)转换
  3. 重点坑:右值引用变量本身是左值,再次传递需要move
3.2.2 示例
cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
    int x = 10;
    // 左值引用绑定左值
    int& r1 = x;

    // const左值引用绑定右值
    const int& r2 = 100;

    // 右值引用绑定右值
    int&& r3 = 200;

    // 左值转右值再绑定
    int&& r4 = move(x);

    // 坑:r3是右值引用变量,自身是左值,直接绑定报错
    // int&& r5 = r3; 报错
    int&& r5 = move(r3); // 正确
    return 0;
}

3.3 引用延长临时对象生命周期

解释:普通临时对象一行代码结束就销毁;const T&T&&绑定临时变量,会延长临时对象生命周期到引用变量销毁。

示例:

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;
int main()
{
    string s1 = "hello";
    // 临时对象s1+s1生命周期延长
    string&& r = s1 + s1;
    r += " world"; // 非const右值引用可修改
    cout << r << endl;
    return 0;
}

3.4 重载函数自动匹配规则

解释:函数同时写三种重载,编译器自动根据实参类型匹配对应版本:左值匹配T&、const左值匹配const T&、右值匹配T&&

示例:

cpp 复制代码
#include <iostream>
using namespace std;

void func(int& x) { cout << "匹配左值引用" << endl; }
void func(const int& x) { cout << "匹配const左值引用" << endl; }
void func(int&& x) { cout << "匹配右值引用" << endl; }

int main()
{
    int a = 10;
    const int b = 20;
    func(a);        // 左值
    func(b);        // const左值
    func(30);       // 纯右值
    func(move(a));  // move后右值
    return 0;
}

3.5 移动构造、移动赋值(核心提效)

3.5.1 通俗解释

string/vector这种内部开堆内存的类,拷贝构造会完整复制堆内存(慢);移动构造直接偷临时对象的堆内存指针,不用重新分配内存,速度大幅提升。

  • 移动构造:类名(类名&& 临时对象)
  • 移动赋值:类名& operator=(类名&& 临时对象)
3.5.2 极简模拟string示例
cpp 复制代码
#include <iostream>
#include <cstring>
using namespace std;

class MyString
{
private:
    char* _str;
public:
    // 普通构造
    MyString(const char* s)
    {
        cout << "普通构造" << endl;
        _str = new char[strlen(s)+1];
        strcpy(_str, s);
    }
    // 拷贝构造(深拷贝,慢)
    MyString(const MyString& s)
    {
        cout << "拷贝构造" << endl;
        _str = new char[strlen(s._str)+1];
        strcpy(_str, s._str);
    }
    // 移动构造(偷资源,快)
    MyString(MyString&& s)
    {
        cout << "移动构造" << endl;
        // 直接交换指针,不新开内存
        swap(_str, s._str);
    }
    ~MyString() { delete[] _str; }
};

MyString getStr()
{
    return MyString("test"); // 返回临时右值,触发移动
}

int main()
{
    MyString s1 = getStr();
    MyString s2 = move(s1); // move转右值,调用移动构造
    return 0;
}

3.6 值类别细分(了解即可)

  1. 纯右值prvalue:字面量、临时对象(C++98老式右值)
  2. 将亡值xvalue:move(变量)、返回T&&函数结果
  3. 泛左值glvalue = 普通左值 + 将亡值

3.7 引用折叠 + 万能引用

3.7.1 折叠规则(死记)

只有 T&& &&T&&;其他所有引用组合全部折叠为左值引用T&

3.7.2 万能引用:模板T&&

解释:模板参数写T&&不是单纯右值引用,实参传左值自动变成左值引用,传右值变成右值引用,叫万能引用。

示例:

cpp 复制代码
#include <iostream>
using namespace std;

template<class T>
void test(T&& x) // 万能引用
{
}

int main()
{
    int a = 10;
    test(a);    // 传左值 → T推导int& → 折叠int&
    test(20);   // 传右值 → T推导int → int&&
    test(move(a));
    return 0;
}

3.8 完美转发 std::forward

解释:万能引用接收右值后,变量本身是左值,向下传参会丢失右值属性;forward<T>(x)保留原本左/右值属性。

示例:

cpp 复制代码
#include <iostream>
using namespace std;

void func(int&& x) { cout << "右值版本" << endl; }

template<class T>
void wrapper(T&& x)
{
    // func(x); // 报错,x是左值
    func(forward<T>(x)); // 正确,还原右值属性
}

int main()
{
    wrapper(100);
    return 0;
}

4 可变参数模板

4.1 基础语法

解释:template<class... Args>代表参数包 ,能接收任意数量、任意类型参数;sizeof...(args)编译期统计参数个数。

示例:

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

template<class... Args>
void print(Args... args)
{
    cout << "参数总个数:" << sizeof...(args) << endl;
}

int main()
{
    print();
    print(10);
    print(10, "abc", 3.14);
    return 0;
}

4.2 参数包递归展开

解释:不能用for循环遍历参数包,编译期递归拆解,需要一个无参终止函数。

示例:

cpp 复制代码
#include <iostream>
using namespace std;
// 终止函数
void show() { cout << endl; }
// 递归拆解参数包
template<class T, class... Args>
void show(T val, Args... args)
{
    cout << val << " ";
    show(args...);
}

int main()
{
    show(1,2,"hello",3.14);
    return 0;
}

4.3 emplace系列容器接口(可变参数实际用途)

4.3.1 通俗解释

push_back:先创建临时对象,再移动/拷贝进容器;

emplace_back:直接把构造参数传给容器内部,原地构造对象,省去临时对象,效率更高。

4.3.2 示例
cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
using namespace std;

class Student
{
public:
    Student(string name, int age)
    {
        cout << "构造学生对象" << endl;
    }
};

int main()
{
    vector<Student> v;
    // emplace直接传构造参数,不用构造临时Student
    v.emplace_back("张三", 18);
    // push_back需要先构造临时对象
    v.push_back(Student("李四", 20));
    return 0;
}

5 C++11 类新语法

5.1 自动生成移动构造/移动赋值

解释:C++98编译器默认生成4个函数:无参构造、析构、拷贝构造、拷贝赋值;C++11新增默认移动构造、移动赋值

生成条件:你没有手动写析构、拷贝构造、拷贝赋值任意一个,编译器自动生成移动函数。

5.2 类内成员缺省值

解释:声明成员变量时直接赋值,初始化列表没手动初始化时自动使用该默认值。

示例:

cpp 复制代码
#include <iostream>
using namespace std;
class Person
{
private:
    int age = 18; // 类内缺省值
public:
    int getAge() { return age; }
};
int main()
{
    Person p;
    cout << p.getAge() << endl; // 输出18
    return 0;
}

5.3 =default=delete

  1. =default:强制编译器生成默认函数(手动写了拷贝构造后,想要自动移动构造就用这个)
  2. =delete:直接禁用该函数,调用就编译报错,替代C++98私有禁用写法
    示例:
cpp 复制代码
class Person
{
public:
    Person() = default; // 强制生成默认构造
    Person(const Person&) = delete; // 禁用拷贝构造
};
int main()
{
    Person p1;
    // Person p2 = p1; 编译报错,拷贝构造被删除
    return 0;
}

5.4 override / final

  1. override:修饰虚函数,强制编译器检查是否正确重写父类虚函数,函数名写错直接报错
  2. final:修饰类→禁止被继承;修饰虚函数→禁止子类重写
    示例:
cpp 复制代码
#include <iostream>
using namespace std;
class Base
{
public:
    virtual void func() {}
};
class Son : public Base
{
public:
    // 正确重写,编译器校验
    void func() override {}
    // void fun() override {} 报错,父类没有fun虚函数
};

// final类,不能继承
class A final {};
// class B : public A {}; 报错

6 STL 容器更新

6.1 新增容器

std::array(固定大小数组)、forward_list(单向链表)、unordered_map/unordered_set(哈希表,日常最常用)

6.2 通用新特性

  1. 全部支持{}批量初始化(initializer_list)
  2. 新增emplace/emplace_back原地构造接口
  3. push_back/insert支持右值引用版本,自动移动资源
  4. cbegin/cend常量迭代器,返回const迭代器
  5. 支持范围for循环 ,简化遍历
    范围for示例:
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int> v = {1,2,3,4,5};
    // 范围for遍历
    for(auto x : v)
    {
        cout << x << " ";
    }
    return 0;
}

7 Lambda 匿名函数(初学者高频使用)

7.1 完整语法

[捕获列表](参数)->返回类型{函数体}

  • []捕获列表:不能省略,抓取外层局部变量
  • ()参数:无参数可省略,用mutable时不能省
  • ->返回值:返回类型统一可省略,编译器自动推导
  • {}函数体:不可省略

7.2 捕获规则(重点)

  1. [a] 值捕获:复制变量,lambda内是副本,不能修改
  2. [&a] 引用捕获:直接操作外部原变量,可修改
  3. [=] 隐式全部值捕获;[&]隐式全部引用捕获
  4. 混合捕获:[=, &x]其余值捕获,x引用;[&, x]其余引用,x值捕获
  5. mutable:解除值捕获变量const限制,只能修改内部副本,不影响外部

7.3 完整示例

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main()
{
    vector<int> v = {3,1,4,2};
    int base = 10;
    // lambda排序,[=]值捕获base
    sort(v.begin(), v.end(), [=](int a, int b)
    {
        return a + base < b + base;
    });
    for(auto x : v) cout << x << " ";

    // mutable修改副本
    int num = 100;
    auto f = [num]()mutable
    {
        num++;
        cout << num << endl;
    };
    f();
    cout << num << endl; // 外部num不变,依旧100
    return 0;
}

7.4 底层原理

编译器自动生成一个匿名仿函数类,捕获的变量作为类成员;调用lambda等价于调用仿函数operator()

8 可调用对象包装器 function & bind

8.1 std::function

8.1.1 解释

头文件<functional>,统一包装所有可调用对象(普通函数、lambda、仿函数、成员函数),统一类型方便存储、传参。

8.1.2 示例
cpp 复制代码
#include <iostream>
#include <functional>
using namespace std;

int add(int a, int b) { return a+b; }

int main()
{
    // 包装普通函数
    function<int(int,int)> f1 = add;
    // 包装lambda
    function<int(int,int)> f2 = [](int a,int b){return a*b;};

    cout << f1(2,3) << endl;
    cout << f2(2,3) << endl;
    return 0;
}

8.2 std::bind 函数适配器

8.2.1 解释

绑定固定参数、调整参数顺序、减少参数数量;_1/_2是占位符,代表新函数的参数。

8.2.2 示例
cpp 复制代码
#include <iostream>
#include <functional>
using namespace std;
using placeholders::_1;
using placeholders::_2;

int sub(int a, int b) { return a - b; }

int main()
{
    // 颠倒参数顺序
    auto f1 = bind(sub, _2, _1);
    cout << f1(10,5) << endl; // 5-10=-5

    // 固定第一个参数为100,只传第二个
    auto f2 = bind(sub, 100, _1);
    cout << f2(10) << endl; // 100-10=90
    return 0;
}

9 其余C++11基础特性(简要入门介绍)

9.1 auto / decltype

  • auto:自动推导变量类型,不用手写复杂类型(迭代器、lambda常用)
  • decltype(表达式):获取表达式对应的类型
cpp 复制代码
auto a = 10;
decltype(a) b = 20;

9.2 constexpr

修饰常量/函数,编译期就能计算结果,运行期零开销。

9.3 智能指针

unique_ptr/shared_ptr/weak_ptr,自动释放堆内存,不用手动delete,杜绝内存泄漏。

9.4 标准库拓展

原生多线程、正则表达式库,不用第三方库即可实现并发、字符串匹配。

相关推荐
曹牧1 小时前
C#:Type
开发语言·c#
间歇性努力持续性发呆的野生快乐选手1 小时前
dfs回溯,bfs枚举,完全背包
c++·算法·深度优先·宽度优先
小僧景贤2 小时前
嵌入式C语言 第十一篇:成长路线|嵌入式C工程师完整进阶学习路径(从零到工程级落地|含周期+实战项目)
c语言·开发语言·学习
Brilliantwxx2 小时前
【Linux】自动化构建工具 make 与 Makefile
linux·运维·服务器·开发语言·自动化
码工许师傅2 小时前
一文读懂《Effective C++ 第三版》的55条黄金法则
c++
灵晔君2 小时前
【Linux】进程(四)——进程虚拟地址空间
linux·c语言·开发语言
萧瑟余晖2 小时前
Java深入解析篇十八之响应式编程
java·开发语言
看浪的路人2 小时前
第5讲:代码审查与 Bug 检测
开发语言·windows·python
netccdn2 小时前
Hough变换检测直线(Matlab)
开发语言·计算机视觉·matlab