欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 旅游 > C++11

C++11

2025/5/17 16:32:29 来源:https://blog.csdn.net/2301_79109608/article/details/146964304  浏览:    关键词:C++11

C++11 新增关键字总结与归纳

一、auto 关键字(自动类型推导)
  1. 用途
    由编译器自动推断变量类型,简化代码编写。

  2. 语法

    auto 变量名 = 初始值; // 类型由初始值推导
  3. 示例

    auto x = 42;           // x 推导为 int
    auto it = map.begin(); // it 推导为迭代器类型
  4. 限制

    • 不能用于函数参数。

    • 不能定义类的非静态成员变量。

    • 不能定义数组(如 auto arr[] = {1, 2, 3}; 非法)。

    • 不能用于模板参数(如 Test<auto> C2; 非法)。

二、nullptr 关键字(空指针常量)
  1. 用途
    明确表示空指针,解决 NULL(可能被定义为 0 或 (void*)0)的歧义。

  2. 示例

    void func(int* ptr);
    func(nullptr);  // 明确调用指针版本的重载函数Test test;
    test.TestWork(NULL);    // 可能调用 int 版本(若 NULL 定义为 0)
    test.TestWork(nullptr); // 明确调用 int* 版本
  3. 优势

    • 类型安全,避免重载函数时的歧义。

三、统一初始化语法(初始化列表)
  1. 用途
    支持使用花括号 {} 初始化容器、类成员、数组等,使代码更简洁。

  2. 示例

    int arr[]{1, 2, 3};                     // 数组初始化
    vector<int> v{1, 2, 3};                  // vector 初始化
    map<string, int> m{{"c1", 28}, {"c2", 31}}; // map 初始化
    class Test {int num{10};                         // 类成员初始化
    };
  3. 特点

    • 适用于所有标准容器和自定义类型(需支持 std::initializer_list)。

四、基于范围的 for 循环
  1. 用途
    简化遍历数组、容器、字符串等序列的操作。

  2. 语法

    for (auto& 元素 : 容器) { /* 操作 */ }
  3. 示例

    map<string, float> fruits{{"Apple", 8.2}, {"Banana", 3.7}};
    for (auto& fruit : fruits) {cout << fruit.first << " : " << fruit.second << endl;
    }
  4. 注意

    • 容器需支持迭代器(即提供 begin() 和 end() 方法)。

五、static_assert(编译期断言)
  1. 用途
    在编译阶段检查条件,若不满足则立即报错。

  2. 语法

    static_assert(常量表达式, "错误信息");
  3. 示例

    static_assert(sizeof(int*) == 8, "64 位系统不支持!");
  4. 特点

    • 条件必须是编译期可计算的常量表达式。

    • 适用于检查平台特性、类型大小等。

关键对比与注意事项

关键字/特性核心作用典型场景注意事项
auto自动类型推导简化迭代器、复杂类型声明不可用于函数参数或非静态成员变量
nullptr明确表示空指针重载函数中区分指针与整型替代 NULL,提升类型安全
统一初始化语法统一容器、类成员的初始化方式初始化列表、类成员默认值需容器支持 initializer_list
范围 for简化遍历操作遍历数组、容器、字符串容器需提供迭代器接口
static_assert编译期检查条件验证类型大小、平台特性条件必须是编译期常量表达式

左值和右值总结与归纳

一、左值(lvalue)
  1. 定义
    可出现在赋值语句左侧的表达式,表示对象的身份(内存位置)。

  2. 特性

    • 可寻址:可通过 & 获取地址。

    • 可修改(除非被 const 限定)。

  3. 示例

    int x = 5;       // x 是左值
    x = 10;          // x 可被赋值
    int* p = &x;     // 获取 x 的地址
二、右值(rvalue)
  1. 定义
    不能出现在赋值语句左侧的表达式,通常是临时值或字面量。

  2. 分类

    • 纯右值(prvalue):如字面量 42、函数返回的临时对象。

    • 将亡值(xvalue):即将被销毁但可通过移动语义转移资源的对象(如 std::move 的返回值)。

  3. 示例

    int func() { return 42; }  // 返回的 42 是右值
    int x = func();            // 右值赋给左值 x
    int&& rr = 42;             // 右值引用绑定字面量
三、右值引用(Rvalue Reference)
  1. 语法类型&& 变量名 = 右值;

  2. 特性

    • 必须初始化,且通常只能绑定右值。

    • 允许修改绑定的右值(延长其生命周期)。

  3. 示例

    int&& num2 = 10;  // 右值引用绑定字面量
    num2++;           // 允许修改(输出 num2 = 11)
四、移动语义(Move Semantics)
  1. 目的
    避免不必要的深拷贝,通过转移资源提升性能。

  2. 实现方式

    • 移动构造函数:接受右值引用参数,直接“窃取”资源。

    • 移动赋值运算符:类似逻辑。

  3. 示例

    // 移动构造函数
    String::String(String&& s) {this->str = s.str;  // 转移资源s.str = nullptr;    // 置空源对象指针
    }
  4. 运行结果对比

    • 无移动语义:触发深拷贝,频繁分配/释放内存。

    • 有移动语义:直接转移资源,减少拷贝开销。

五、std::move 函数
  1. 作用
    将左值强制转换为右值引用,触发移动语义。

  2. 注意

    • 转换后的对象可能处于“有效但未定义”状态(如指针置空)。

    • 适用于生命周期即将结束的对象。

  3. 示例

    String s1("putty");
    String s2(std::move(s1));  // 强制转为右值,调用移动构造函数
六、关键总结
概念特点应用场景
左值可寻址、可修改、有持久性变量、对象实例、赋值操作左侧
右值临时性、不可寻址、不可直接修改字面量、函数返回的临时对象
右值引用绑定右值,允许修改右值,延长生命周期移动语义、完美转发
移动语义通过转移资源避免拷贝,提升性能大型对象传递、资源管理类(如容器)
std::move将左值转为右值引用,强制触发移动语义优化资源转移、避免冗余拷贝
七、注意事项
  1. 移动后的对象状态
    使用 std::move 后,原对象资源可能被转移,需谨慎操作。

  2. 编译器优化
    返回值优化(RVO)可能跳过拷贝/移动构造函数,需通过 -fno-elide-constructors 禁用优化观察行为。

  3. 代码健壮性
    实现移动语义时,需确保源对象处于安全状态(如指针置空)。

C++ Lambda 表达式总结与归纳

一、基本语法

Lambda 表达式的基本语法如下:

[捕获列表](参数列表) mutable -> 返回类型 { 函数体 };
  • 捕获列表(Capture List):指定外部变量如何被捕获(按值 [x] 或按引用 [&x])。

  • 参数列表(Parameters):与普通函数参数列表一致。

  • mutable:允许修改按值捕获的变量(默认按值捕获的变量是 const)。

  • 返回类型:可省略,编译器根据 return 语句自动推导。

  • 函数体:实现 Lambda 的逻辑。

二、捕获方式

Lambda 表达式通过捕获列表访问外部变量,捕获方式分为以下几类:

捕获形式说明
[]不捕获任何外部变量。
[x, &y]按值捕获 x,按引用捕获 y
[=]按值捕获所有外部变量(隐式值捕获)。
[&]按引用捕获所有外部变量(隐式引用捕获)。
[=, &x]按引用捕获 x,其余变量按值捕获。
[&, x]按值捕获 x,其余变量按引用捕获。
[this]捕获当前类的 this 指针。
三、核心特性与示例
  1. 值捕获与引用捕获

    • 值捕获:外部变量的值在 Lambda 创建时拷贝,后续修改不影响 Lambda 内部值。

      int a = 100;
      auto lambda = [a] { return a + 10; };
      a = 200;  // lambda 内部 a 仍为 100
    • 引用捕获:Lambda 内部直接操作外部变量的引用。

      int a = 100;
      auto lambda = [&a] { a += 10; };
      lambda();  // a 变为 110
  2. mutable 关键字
    允许修改按值捕获的变量(默认不可修改):

    int x = 10;
    auto lambda = [x]() mutable { x++; };  // 合法
  3. 省略格式

    • 省略返回类型:编译器根据 return 语句推导。

      auto lambda = [](int a, int b) { return a + b; };
    • 省略参数列表:无参 Lambda。

      auto lambda = [] { cout << "Hello"; };
  4. 在 STL 算法中的应用

    vector<int> vec = {1, 2, 3, 4, 5};
    // 遍历并打印元素
    for_each(vec.begin(), vec.end(), [](int x) { cout << x << " "; });
    // 查找第一个大于 3 的元素
    auto it = find_if(vec.begin(), vec.end(), [](int x) { return x > 3; });
四、隐式捕获与显式捕获
  1. 隐式捕获

    • [=]:按值捕获所有外部变量。

    • [&]:按引用捕获所有外部变量。

    int x = 10, y = 20;
    auto lambda1 = [=] { return x + y; };  // 按值捕获 x 和 y
    auto lambda2 = [&] { x++; y++; };       // 按引用捕获 x 和 y
  2. 混合捕获

    int x = 10, y = 20;
    auto lambda = [=, &x] { y++; };  // x 按引用捕获,y 按值捕获
五、注意事项
  1. 生命周期问题
    按引用捕获的变量需确保在 Lambda 执行时仍有效。

  2. mutable 的局限
    仅允许修改按值捕获的变量,不影响外部原始变量。

  3. 性能优化
    避免过度使用 [&] 或 [=],显式指定捕获变量更安全高效。

总结对比表

特性值捕获引用捕获
语法[x][&x]
修改外部变量不可修改(需 mutable可直接修改
生命周期影响安全(拷贝值)需确保变量存活
性能可能产生拷贝开销无拷贝开销

C++ 可调用对象与 std::functionstd::bind 总结与归纳

一、可调用对象(Callable Objects)

可调用对象是指可以像函数一样被调用的实体,包括以下类型:

类型定义与示例调用方式
普通函数传统定义的函数。add(10, 20);
成员函数类的成员函数,需通过对象调用。Calc calc; calc.add(10, 20);
Lambda 表达式匿名函数,可捕获外部变量。auto lambda = [](int a, int b) { return a + b; };
函数对象(仿函数)重载了 operator() 的类对象。Add adder; adder(10, 20);
成员函数指针指向类成员函数的指针,需结合对象调用。int (Calc::*funcPtr)(int, int) = &Calc::add; (calc.*funcPtr)(10, 20);
可转换函数指针的类类通过转换运算符返回函数指针,使对象可被直接调用。Calc calc; calc(10, 20);
二、std::function 包装器

std::function 是一个通用的可调用对象包装器,可以存储、复制和调用任何可调用对象(除类成员函数指针外),提供统一的调用接口。

语法与用法
#include <functional>
std::function<返回类型(参数列表)> 变量名;

示例

// 包装普通函数
std::function<int(int, int)> func1 = add;
cout << func1(10, 20); // 输出 30// 包装 Lambda 表达式
auto lambda = [](int a, int b) { return a + b; };
std::function<int(int, int)> func2 = lambda;// 包装函数对象
Add adder;
std::function<int(int, int)> func3 = adder;// 包装绑定后的成员函数(需结合 std::bind)
Calc calc;
auto bound_func = std::bind(&Calc::add, &calc, std::placeholders::_1, std::placeholders::_2);
std::function<int(int, int)> func4 = bound_func;
特点
  • 类型擦除:隐藏具体类型,统一调用接口。

  • 兼容性:支持普通函数、Lambda、函数对象等(成员函数需配合 std::bind)。

  • 延迟执行:可存储可调用对象,在需要时调用。

三、std::bind 绑定器

std::bind 用于将可调用对象与其参数绑定,生成新的可调用对象。主要功能包括:

  • 参数绑定:固定部分参数,生成参数更少的可调用对象。

  • 参数重排序:通过占位符 _1, _2... 调整参数顺序。

语法与用法
#include <functional>
auto 新可调用对象 = std::bind(原可调用对象, 绑定参数列表);

示例

// 绑定普通函数的部分参数
auto bound_add = std::bind(add, 10, std::placeholders::_1);
cout << bound_add(20); // 输出 30(等效于 add(10, 20))// 绑定成员函数
Calc calc;
auto bound_member = std::bind(&Calc::add, &calc, std::placeholders::_1, std::placeholders::_2);
cout << bound_member(10, 20); // 输出 30// 绑定 Lambda 表达式
auto lambda = [](int a, int b) { return a + b; };
auto bound_lambda = std::bind(lambda, std::placeholders::_2, std::placeholders::_1);
cout << bound_lambda(20, 10); // 输出 30(参数顺序交换)
占位符
  • std::placeholders::_1:表示新可调用对象的第一个参数。

  • std::placeholders::_2:表示第二个参数,依此类推。

四、关键对比与注意事项
特性std::functionstd::bind
核心功能统一存储和调用各类可调用对象。绑定参数或调整参数顺序,生成新可调用对象。
支持类型普通函数、Lambda、函数对象、绑定后的成员函数等。所有可调用对象,包括成员函数。
典型场景回调函数、事件处理、通用接口封装。参数适配、延迟执行、函数组合。
注意事项无法直接包装成员函数指针,需结合 std::bind绑定对象的生命周期需确保有效(避免悬空指针)。
五、应用场景与最佳实践
  1. 回调机制
    使用 std::function 存储回调函数,支持动态替换。

    std::function<void(int)> callback;
    callback = [](int x) { cout << "Callback: " << x; };
    callback(42); // 输出 Callback: 42V
  2. 参数适配
    通过 std::bind 适配接口参数。

    void log(int level, const string& msg);
    auto warn_log = std::bind(log, 2, std::placeholders::_1);
    warn_log("Disk full!"); // 等效于 log(2, "Disk full!")
  3. 成员函数封装
    将成员函数绑定到对象,生成可调用对象。

    class Timer {
    public:void start(int interval) { /* ... */ }
    };
    Timer timer;
    auto start_timer = std::bind(&Timer::start, &timer, 1000);
    start_timer(); // 调用 timer.start(1000)
  4. 资源管理
    确保 std::bind 绑定的对象在调用时仍有效(如使用智能指针)。

C++ 智能指针总结与归纳

一、智能指针概述

智能指针是用于管理动态分配内存的类模板,通过自动释放内存减少内存泄漏和悬空指针风险。C++11 支持以下类型:

  • unique_ptr:独占所有权,不可拷贝,可移动。

  • shared_ptr:共享所有权,基于引用计数。

  • weak_ptr:弱引用,不增加引用计数,解决 shared_ptr 循环引用问题。

  • auto_ptr(已废弃):所有权转移语义,存在潜在问题。

二、unique_ptr(独占指针)
  1. 特点

    • 资源唯一归属,离开作用域自动释放。

    • 禁止拷贝,允许移动(通过 std::move)。

  2. 示例

    unique_ptr<String> smart1(new String("hello"));
    unique_ptr<String> smart2 = move(smart1);  // 合法,转移所有权
    // smart1 变为空,smart2 持有资源
  3. 注意事项

    • 禁止赋值或拷贝:smart1 = smart2 或 unique_ptr<String> smart3(smart1) 会编译错误。

    • 优先用于单一所有权场景(如工厂模式返回对象)。

三、shared_ptr(共享指针)
  1. 特点

    • 允许多个指针共享同一对象,通过引用计数管理生命周期。

    • 引用计数为 0 时释放资源。

  2. 核心操作

    shared_ptr<String> s1(new String("hello"));
    shared_ptr<String> s2 = s1;  // 引用计数+1
    cout << s1.use_count();      // 输出 2
  3. 循环引用问题

    • 场景:两个对象互相持有对方的 shared_ptr,导致引用计数无法归零。

    • 解决方案:将其中一个指针改为 weak_ptr

    class AA {shared_ptr<BB> m_bb_ptr;  // 错误:导致循环引用weak_ptr<BB> m_bb_ptr;    // 正确:使用 weak_ptr
    };
四、weak_ptr(弱指针)
  1. 特点

    • 不增加引用计数,不控制对象生命周期。

    • 需通过 lock() 转换为 shared_ptr 访问资源。

  2. 示例

    shared_ptr<String> s_ptr(new String("hello"));
    weak_ptr<String> w_ptr = s_ptr;
    if (!w_ptr.expired()) {auto ptr = w_ptr.lock();  // 转换为 shared_ptrptr->show();
    }
  3. 应用场景

    • 解决 shared_ptr 循环引用。

    • 缓存或观察者模式中避免资源滞留。

五、auto_ptr(已废弃)
  1. 问题

    • 所有权转移时原指针置空,易导致悬空指针。

    auto_ptr<String> smart1(new String("hello"));
    auto_ptr<String> smart2 = smart1;  // smart1 变为空
    smart1->show();                    // 运行时错误!
  2. 替代方案:使用 unique_ptr

六、关键对比与选择建议
类型所有权模型拷贝/移动适用场景
unique_ptr独占仅移动(std::move单一所有者,资源明确归属。
shared_ptr共享允许拷贝多所有者,需共享资源。
weak_ptr弱引用(不拥有)需转换为 shared_ptr解决循环引用或观察者模式。
七、注意事项
  1. 避免裸指针初始化多个 shared_ptr

    String* str = new String("hello");
    shared_ptr<String> s1(str);
    shared_ptr<String> s2(str);  // 错误:重复释放!
  2. 优先使用 make_shared

    auto s_ptr = make_shared<String>("hello");  // 更高效且安全
  3. 循环引用检测:使用 weak_ptr 替代 shared_ptr 成员变量。

总结
  • unique_ptr:轻量级,适用于单一所有权场景。

  • shared_ptr:灵活共享资源,需注意循环引用。

  • weak_ptr:辅助 shared_ptr,解决循环引用问题。

  • 避免使用 auto_ptr,优先选择现代智能指针。

  • 这是本人的学习笔记不是获利的工具,小作者会一直写下去,希望大家能多多监督我
  • 文章会每攒够两篇进行更新发布
  • 感谢各位的阅读希望我的文章会对诸君有所帮助

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词