当前位置: 首页 > news >正文

【C++】C++11 知识点梳理(中)

一、智能指针

C++11 引入了智能指针,用于自动管理动态分配的内存,避免内存泄漏。

1.1 unique_ptr

unique_ptr独占所指向的对象,不支持拷贝,但支持移动语义。

#include <memory> #include <iostream> int main() { // 创建一个 unique_ptr,管理一个 int std::unique_ptr<int> p1(new int(42)); std::cout << *p1 << std::endl; // 输出 42 // 移动语义转移所有权 std::unique_ptr&lt;int&gt; p2 = std::move(p1); // 此时 p1 为空,p2 拥有对象 if (!p1) { std::cout &lt;&lt; "p1 is now empty" &lt;&lt; std::endl; } // 使用 make_unique (C++14 引入,但常与 C++11 一起讨论) auto p3 = std::make_unique&lt;int&gt;(100); return 0; }

1.2 shared_ptr

shared_ptr通过引用计数实现共享所有权,当最后一个shared_ptr被销毁时,对象被释放。

#include <memory> #include <iostream> class MyClass { public: MyClass() { std::cout << "MyClass constructed\n"; } ~MyClass() { std::cout << "MyClass destroyed\n"; } void sayHello() { std::cout << "Hello from MyClass\n"; } }; int main() { std::shared_ptr<MyClass> sp1(new MyClass()); { std::shared_ptr<MyClass> sp2 = sp1; // 引用计数+1 sp2->sayHello(); } // sp2 离开作用域,引用计数-1 // sp1 仍然有效 sp1->sayHello(); return 0; } // sp1 离开作用域,引用计数归零,对象被销毁

1.3 weak_ptr

weak_ptrshared_ptr的弱引用,不增加引用计数,用于解决循环引用问题。

#include <memory> #include <iostream> struct Node { std::shared_ptr<Node> next; std::weak_ptr<Node> prev; // 使用 weak_ptr 避免循环引用 int value; Node(int v) : value(v) {} }; int main() { auto node1 = std::make_shared<Node>(1); auto node2 = std::make_shared<Node>(2); node1-&gt;next = node2; node2-&gt;prev = node1; // 弱引用,不会增加 node1 的引用计数 // 通过 weak_ptr 访问对象 if (auto sp = node2-&gt;prev.lock()) { std::cout &lt;&lt; "Previous node value: " &lt;&lt; sp-&gt;value &lt;&lt; std::endl; } else { std::cout &lt;&lt; "Object has been destroyed\n"; } return 0; }

二、右值引用与移动语义

右值引用(T&&)和移动语义是 C++11 性能优化的核心,允许资源(如动态内存)的“转移”而非“拷贝”。

2.1 左值、右值与右值引用

  • 左值 (lvalue):有名字、有地址的表达式。
  • 右值 (rvalue):临时对象、字面量(除字符串字面量)、返回非引用的函数调用。
  • 右值引用:绑定到右值的引用,用&&声明。
int a = 10; // a 是左值 int& lref = a; // 左值引用 // int& rref = 20; // 错误:不能将左值引用绑定到右值 int&& rref = 20; // 右值引用绑定到字面量 int&& rref2 = std::move(a); // 通过 std::move 将左值转换为右值引用

2.2 移动构造函数与移动赋值运算符

定义了移动语义的类可以高效转移资源。

#include <utility> // for std::move #include <cstring> class String { public: char* data; size_t length; // 构造函数 String(const char* str) { length = strlen(str); data = new char[length + 1]; strcpy(data, str); std::cout &lt;&lt; "Constructor\n"; } // 拷贝构造函数(深拷贝) String(const String&amp; other) { length = other.length; data = new char[length + 1]; strcpy(data, other.data); std::cout &lt;&lt; "Copy Constructor\n"; } // 移动构造函数(资源转移) String(String&amp;&amp; other) noexcept { data = other.data; length = other.length; other.data = nullptr; // 置空原指针,防止重复释放 other.length = 0; std::cout &lt;&lt; "Move Constructor\n"; } // 析构函数 ~String() { delete[] data; } }; int main() { String s1("Hello"); String s2 = s1; // 调用拷贝构造函数 String s3 = std::move(s1); // 调用移动构造函数,s1 的资源被转移 return 0; }

2.3 std::move 与 std::forward

  • std::move:无条件将参数转换为右值引用,用于启动移动语义。
  • std::forward:完美转发,保持参数原有的值类别(左值/右值),用于模板编程。
#include <utility> #include <iostream> void process(int& x) { std::cout << "lvalue: " << x << std::endl; } void process(int&& x) { std::cout << "rvalue: " << x << std::endl; } template<typename T> void relay(T&& arg) { // 使用 std::forward 保持 arg 的原始值类别 process(std::forward<T>(arg)); } int main() { int a = 10; relay(a); // 传递左值,调用 process(int&) relay(20); // 传递右值,调用 process(int&&) return 0; }

三、Lambda 表达式

Lambda 表达式提供了一种简洁的定义匿名函数对象的方式。

3.1 基本语法

[capture] (parameters) -> return_type { body }
  • capture:捕获列表,指定哪些外部变量在 lambda 体内可用。
  • parameters:参数列表(可选)。
  • return_type:返回类型(可选,可自动推导)。
  • body:函数体。

3.2 捕获方式

#include <iostream> #include <vector> #include <algorithm> int main() { int x = 10; int y = 20; // 值捕获 auto lambda1 = [x]() { return x; }; // 捕获 x 的副本 // 引用捕获 auto lambda2 = [&amp;y]() { return ++y; }; // 捕获 y 的引用 // 隐式值捕获所有变量 auto lambda3 = [=]() { return x + y; }; // 捕获所有外部变量的副本 // 隐式引用捕获所有变量 auto lambda4 = [&amp;]() { return ++x + ++y; }; // 捕获所有外部变量的引用 // 混合捕获 auto lambda5 = [x, &amp;y]() { return x + y; }; // x 值捕获,y 引用捕获 std::cout &lt;&lt; lambda1() &lt;&lt; std::endl; // 10 std::cout &lt;&lt; lambda2() &lt;&lt; std::endl; // 21, y 变为 21 std::cout &lt;&lt; y &lt;&lt; std::endl; // 21 // 在算法中使用 lambda std::vector&lt;int&gt; vec = {1, 2, 3, 4, 5}; int threshold = 3; // 捕获 threshold 用于比较 auto it = std::find_if(vec.begin(), vec.end(), [threshold](int val) { return val &gt; threshold; }); if (it != vec.end()) { std::cout &lt;&lt; "First element &gt; " &lt;&lt; threshold &lt;&lt; " is " &lt;&lt; *it &lt;&lt; std::endl; } return 0; }

3.3 泛型 Lambda (C++14) 与 mutable

#include <iostream> int main() { // mutable 允许修改按值捕获的变量(修改的是副本) int count = 0; auto counter = count mutable { return ++count; // 修改的是捕获的副本,不影响外部的 count }; std::cout << counter() << std::endl; // 1 std::cout << counter() << std::endl; // 2 std::cout << "Original count: " << count << std::endl; // 0 // C++14 泛型 Lambda(使用 auto 参数) auto add = [](auto a, auto b) { return a + b; }; std::cout &lt;&lt; add(1, 2) &lt;&lt; std::endl; // 3 std::cout &lt;&lt; add(1.5, 2.3) &lt;&lt; std::endl; // 3.8 return 0; }
http://www.jsqmd.com/news/1150002/

相关文章:

  • 可微光栅化 vs 可微路径追踪:3 大核心差异与 2 类应用场景选择
  • macOS Sonoma 14.5 安装 GCC 13.2:3步解决与系统Clang的命名冲突
  • 微信公众号自动回复机器人 3 种方案对比:原生接口 vs 第三方平台 vs 自建 NLP
  • VisualCppRedist AIO:一站式解决Windows DLL缺失问题的终极解决方案
  • Meta推出AI图像生成模型Muse Image,多平台免费用,还将拓展更多应用场景!
  • Adobe Illustrator 2025合规获取与替代方案全指南
  • Linux LVM 逻辑卷管理实战:3步完成磁盘扩容与快照备份
  • Linux backtrace 实战:捕获 SIGSEGV/SIGFPE 信号并定位动态库崩溃行号
  • DLSS Swapper终极教程:3分钟学会智能切换DLSS版本,游戏性能提升40%+
  • Chrome DevTools 3种刷新模式详解:F5、Ctrl+F5 与清空缓存的 HTTP 请求差异
  • PHP 5.3-8.0 Phar反序列化深度解析:从文件结构到内核函数php_var_unserialize
  • 通达OA v11.7 auth_mobi.php 漏洞深度剖析:从SQL查询到PHPSESSID劫持的3步攻击链
  • 终极指南:如何在5分钟内安装和使用Minecraft X-Ray矿物探测模组
  • SQL注入防御视角:3种WAF规则如何识别与拦截UNION攻击
  • 纽扣电池供电优化:NBM5100A与PIC18F4550的低功耗设计
  • PHP 反序列化代码审计:从 1 个 HelloPhp 类到 5 种魔术方法风险点排查
  • VINS-Mono 1.0 部署实战:Ubuntu 20.04 + ROS Noetic 避坑 3 要点
  • Struts2 S2-009 (CVE-2011-3923) 漏洞原理深度解析:从OGNL绕过到RCE的3层逻辑
  • Metasploit 6.4 安卓后门 APK 生成与免杀:3 种混淆技术绕过基础检测
  • Apache Flink <=1.11.2 未授权上传漏洞:从 Jar 包到 RCE 的 3 层防御绕过分析
  • RSS Feed 安全与性能优化:5个关键配置防止内容盗用与过载
  • 瑞数5.5 逆向实战:基于正则定位与日志插装的动态代码分析
  • Windows 资源监视器 vs Process Explorer:3 个典型场景下的进程排查效率对比
  • 3个步骤轻松掌握Escrcpy:让电脑无线控制Android手机
  • Apache Shiro 1.2.4 反序列化漏洞深度解析:从RememberMe Cookie到RCE的完整攻击链
  • 校友邦小程序 v1.6.36 签到加密逆向:从JS到PHP的3步完整迁移
  • ENVI5.6/Classic 协同处理:WorldView-2数据4步城市绿地提取全流程
  • autorun.inf 文件深度解析:从图标自定义到U盘病毒防范的10年演变
  • 程序员就业:用一次真实复盘,讲清该怎么学
  • SchoolCMS 实战渗透:从弱口令到Shell的5类漏洞复现与修复指南