C++11 特性

1、智能指针(RAII 自动资源管理)

类型 特点 创建方式
unique_ptr 独占所有权,不能复制,只能移动。适合独享资源(如文件、连接) make_unique<T>(args...)
shared_ptr 多个指针共享所有权,引用计数为 0 时自动释放资源 make_shared<T>(args...)
weak_ptr 弱引用,不增加引用计数,配合 shared_ptr 解决循环引用问题 shared_ptr 构造
cpp 复制代码
std::unique_ptr<int> ptr1 = std::make_unique<int>(10);      // 独占
std::shared_ptr<int> ptr2 = std::make_shared<int>(20);      // 引用计数
std::weak_ptr<int> weak = ptr2;             // 弱引用
if (auto spt = weak.lock()) { cout << *spt; } // 判断是否有效

2、Lambda 表达式(匿名函数)

语法结构: [捕获列表](参数列表) mutable -> 返回类型 {函数体}

捕获方式 含义
[] 不捕获任何变量
[=] 按值捕获所有变量
[&] 按引用捕获所有变量
[x] / [&x] 按值/按引用捕获单个变量
[=, &x] 值捕获其余,引用捕获 x
[this] 捕获当前对象指针
cpp 复制代码
int a = 10;
auto f = [=]() { return a + 1; };   // 外部 a 不变
auto g = [&]() { a += 2; };         // 外部 a 改变
auto h = [a]() mutable { a += 5; }; // 外部 a 不变

用途:排序、自定义操作、回调、线程函数、STL 算法等。

3、mutable 关键字(突破 const)

应用位置 作用说明
类成员 允许在 const 成员函数中修改此变量
lambda 捕获按值的变量可在函数体中被修改
cpp 复制代码
class A {
    mutable int count = 0;
    void f() const { count++; }
};

int a = 0;
auto h = [a]() mutable { a += 5; }; // 外部 a 不变

4、左值与右值 & std::move & std::forward

(1)左值和右值
类型 特点 示例
左值 · 具有地址,存储在内存中; · 可以出现在 ' = ' 左侧; · 可以取地址; · 变量、对象、数组元素都是左值; int a = 1; // 变量是左值 a = 10; // 可以出现在 ' = ' 左侧 int *b = &a; // 可以取地址
右值 · 通常没有地址,存储在寄存器或临时内存中 · 不可以出现在 ' = ' 左侧; · 不能取地址(右值可以绑定到const左值引用); · 字面量、表达式计算结果都是右值; int x = 1 + 2; // (1 + 2) 为右值 int *p = &(1+2); // ❌ 右值不能取地址
(2)左值引用
cpp 复制代码
int a = 1;              // a是左值
int& c = a;             // 左值引用

int& d = 1+2;           // ❌ 右值不能绑定到左值引用
const int& y2 = 1 + 2;  // 绑定到const 左值引用
(3)右值引用 & 移动语义

**std::move的作用:**将左值转换为右值,以触发移动语义,不会真正 ' 移动 ' 数据,只是改变对象的属性;用于触发移动构造和移动赋值,避免深拷贝,提高性能。

cpp 复制代码
int&& a= 1;                     // 右值引用

int b = 10;
int&& c= std::move(b);          // 将左值x用std::move转换为右值,绑定到c

std::string s1 = "abc";
std::string s2 = std::move(s1); // 触发移动构造,避免深拷贝
(4)完美转发

**std::forward的作用:**泛型函数在传递参数时,无法保留参数的左值/右值属性;导致额外的拷贝或移动构造;使用 std::forward 可避免这种情况,实现高效传参。

在模板函数中,将参数以其原始类型(左值/右值)传递给目标函数,称为完美转发。

  • 依赖 C++11 的 万能引用(T&&);

  • 通过 std::forward<T>(arg) 实现。

cpp 复制代码
void target(int& x) { cout << "lvalue: " << x << endl; }
void target(int&& x){ cout << "rvalue: " << x << endl; }

template<typename T>
void wrapper(T&& v) {
    target(std::forward<T>(v));
}

int main(){
    int a = 5;
    wrapper(a);    // 调用 lvalue 版本
    wrapper(10);   // 调用 rvalue 版本
}

5、类型转换

类型 用途与说明
static_cast<T> 编译期安全转换,适用于基本类型转换和上行转换(派生类到基类)。
dynamic_cast<T> 运行时安全下行转换(基类到派生类),依赖 RTTI,基类需包含虚函数。
const_cast<T> 去除 const 限定,但源对象不能是 const
reinterpret_cast<T> 强制类型转换,转换原生内存表示,用于指针和整数之间转换。
(1)static_cast静态转换

基本类型转换上行转换(派生类 --->基类)

cpp 复制代码
/*基本数据类型转换*/
double d = 3.14;
int i = static_cast<int>(d);
cout << i << endl; 

/*向上转换: 派生类  ----> 基类*/
class Base{
public:
    int a;
    Base() {}
    Base(int val) : a(val){}

    virtual ~Base() = default;
};

class Derived : public Base{
    public:
    int b = 100;
    Derived(){};
    Derived(int val) : b(val){
        this->a = b;
    }
};

// 向上转换: Derived --> Base
Derived derived(10);
Base* base = static_cast<Base*>(&derived);
cout << base->a << endl;

// 向下转换: Base --> Derived
// 使用static_cast<T>是❌的
Base base1(10);
Derived* derived1 = static_cast<Derived*>(&base1);
// 向下转换时,derived1指向的数据不包含Derived的特有部分,后续使用derived1可能会导致崩溃或错误
cout << derived1->b << endl;
(2)dynamic_cast动态转换

向下转换: 基类 ---> 派生类,注意:基类必须要有虚函数,否者dynamic_cast无法执行正确的运行时检查

cpp 复制代码
class Base{
    public:
    virtual ~Base() = default; // 必须有虚函数
};

class Derived : public Base{
    public:
    void hello(){
        cout << "hello!" << endl;
    }
};

int main(){
    // 向下转换: Base --> Derived
    Base *base = new Derived();
    Derived* derived = dynamic_cast<Derived*>(base);
    if(derived){
        derived->hello(); // 转换成功
    }else{
        cout << "conversion failed!" << endl;
    }
    delete derived;

    return 0;
}
(3)const_cast

修改可变数据(去除const限定符):如果对象本身不是const,通过const_cast去除指针的const属性是运行的

cpp 复制代码
void modify(const char* str){
	// 形参str被const限定,不能修改
	// str[0] = 'H';

    // const_cast修饰字符指针是安全的
    char* p = const_cast<char*>(str);
    p[0] = 'H';
}
int main(){
    // 字符串字面量即 "hello" 在 C++ 中是 const char[] 类型,即只读的
    // 试图强转去掉 const,但如果底层的内存本身是只读的(如放在代码段的只读区),
    // 就会导致运行时崩溃 或 未定义行为。
    // const char* str = "hello";
    // 想修改字符串内容,应使用可修改的数组
    char str[] = "hello";
    modify(str);
    cout << str << endl;
    
    // a本身是const
    const int a = 10;
    // 通过const_cast将地址转换为int*是未定义行为
    int* b = const_cast<int*>(&a);
    *b = 20; // 尝试修改只读数据
    cout << a << endl; // 不会修改
    
    return 0;
}
(4)reinterpret_cast重解释转换

指针与整数之间转换

cpp 复制代码
//指针与整数之间转换:
int a = 10;
// 将指针转换为整数
uintptr_t addr_a = reinterpret_cast<uintptr_t>(&a);
// 再转换回指针
int* ptr_a = reinterpret_cast<int*>(addr_a);
cout << *ptr_a << endl;

// ❌写法,不同类型指针互相转换
double d = 10;
// 将double指针转换为int指针
int* addr_d = reinterpret_cast<int*>(&d);
cout << *addr_d << endl; // 输出是不正确的

6、auto & decltype

(1)auto

用于自动推断变量类型,必须要给值:

注意:const类型变量推断的时候还是要加const;

cpp 复制代码
auto x = 3.14;
auto y = 1;
auto z = 'z';

vector<int> vec{1,2,3,4,5};
for(auto it = vec.begin(); it != vec.end(); ++it){
    cout << *it << " ";
}

cout << endl;

for(auto &v : vec){
    cout << v << " ";
}

const int b = 10;
const auto a = b;
(2)decltype

用于获取表达式的类型,不同与auto,不会立即对变量求值

后置返回类型:不知道函数返回值类型的场景,就可以使用后置返回类型

cpp 复制代码
decltype(x) y;          // double

template<typename T1, typename T2>
auto add(T1 a, T2 b) -> decltype(a + b){
    return a + b;
}
int main(){
    cout << add(10, 10) << endl;
    return 0;
}
(3)autodecltype配合使用场景
cpp 复制代码
// 下面的场景,通过改变n来改变q是不行的
int q = 10;
int& p = q;
auto n = p;
cout << q << endl;  // 10
n = 10;
cout << q << endl;  // 10

// 通过用decltype来修饰auto,可以实现上述场景
int q = 10;
int& p = q;
decltype(auto) n = p;
cout << q << endl; // 10
n = 20;
cout << q << endl; // 20

7. std::function(通用函数封装器)

std::function 是 C++11 引入的通用函数封装器,可以封装任意可调用对象,如 lambda、函数指针、成员函数、bind 表达式。

(1)基本用法
cpp 复制代码
#include <functional>
#include <iostream>
using namespace std;

class A {
public:
    void show(const string& msg) const {cout << "Msg: " << msg << endl;}
};
void hello(string s) { cout << "Hello " << s << endl; }
// 统一回调接口
void runCallback(const function<void(int)>& callback) {
    callback(100);
}

int main(){
    // 普通函数
    function<void(string)> f1 = hello;
    f1("World");

    // Lambda表达式 
    function<int(int,int)> f2 = [](int a,int b){ return a+b; };
    cout << f2(2,3) << endl;
    
    // 成员函数绑定
    A a;
    auto f3 = std::bind(&A::show, &a, placeholders::_1);
    f3(42);

    // 回调函数绑定
    runCallback([](int val) {
        cout << "Callback with: " << val << endl;
    });
}
(2)什么场景下用std::function
必须用 std::function 的场合 原因
✅封装 lambda(捕获变量) 函数指针不能表示带捕获的 lambda
✅封装成员函数 需要对象上下文,函数指针无法存储
✅封装 bind / 仿函数 bind 生成的是复杂类型,函数指针无法兼容
✅存储多种函数类型 函数指针类型单一,不支持统一封装
✅参数回调统一接口 使用 std::function 可以实现统一的函数调用方式
a、捕获变量的 Lambda
cpp 复制代码
int x = 10;
auto lambda = [x](int y) { return x + y; };

// std::function 可以封装捕获 lambda
std::function<int(int)> f = lambda;
cout << f(5) << endl;  // 输出 15

// ❌ 函数指针不行:lambda 有捕获,不能转换成函数指针
b、成员函数绑定 + 参数绑定
cpp 复制代码
class A {
public:
    void show(const string& msg) const {
        cout << "Msg: " << msg << endl;
    }
};

int main(){
    A a;
	auto func = std::bind(&A::show, &a, std::placeholders::_1);

	// std::function 封装 bind 后的结果
	std::function<void(const string&)> f = func;
	f("Hello");

	// ❌ 函数指针无法绑定成员函数 + 对象一起
}
c、函数容器
cpp 复制代码
vector<function<void(int)>> funcs;

funcs.push_back([](int x) { cout << "Lambda: " << x << endl; });
funcs.push_back([](int x) { cout << "Square: " << x * x << endl; });

// 调用全部
for (auto& f : funcs) {
    f(3);
}

// ❌ 函数指针不支持放在容器里调用不同类型的函数。

8. nullptr

类型安全空指针

优势 说明
✅ 类型安全 nullptr 是一个真正的指针类型,避免与整数混淆
✅ 函数重载清晰 区分 intvoid* 参数,解决函数重载歧义
✅ 更清晰的语义表达 明确表示"空指针",比 NULL0 更直观
✅ 支持模板和泛型编程 nullptr 在模板中不会引起类型推导错误
cpp 复制代码
void f(int) { cout<<"int\n"; }
void f(char*){ cout<<"ptr\n"; }

int main(){
    f(nullptr); // 调用 ptr 版本
    f(NULL);    // 输出 "int",因为 NULL 被视为 0
}
相关推荐
Jay_51513 分钟前
C++多态与虚函数详解:从入门到精通
开发语言·c++
xiaolang_8616_wjl1 小时前
c++文字游戏_闯关打怪
开发语言·数据结构·c++·算法·c++20
FrostedLotus·霜莲2 小时前
C++主流编辑器特点比较
开发语言·c++·编辑器
liulilittle6 小时前
深度剖析:OPENPPP2 libtcpip 实现原理与架构设计
开发语言·网络·c++·tcp/ip·智能路由器·tcp·通信
十年编程老舅7 小时前
跨越十年的C++演进:C++20新特性全解析
c++·c++11·c++20·c++14·c++23·c++17·c++新特性
真的想上岸啊9 小时前
学习C++、QT---18(C++ 记事本项目的stylesheet)
开发语言·c++·学习
m0_552200829 小时前
《UE5_C++多人TPS完整教程》学习笔记40 ——《P41 装备(武器)姿势(Equipped Pose)》
c++·游戏·ue5
丁劲犇9 小时前
用 Turbo Vision 2 为 Qt 6 控制台应用创建 TUI 字符 MainFrame
开发语言·c++·qt·tui·字符界面·curse