C++智能指针深度解析:shared_ptr原理、应用与性能优化
1. 项目概述为什么我们需要共享智能指针在C的世界里内存管理一直是开发者绕不开的“必修课”也是新手最容易“翻车”的地方。手动new和delete就像在悬崖边开车稍有不慎就会导致内存泄漏、悬空指针或者双重释放程序崩溃得让你措手不及。尤其是在构建复杂的对象关系比如多个对象需要共享同一块数据时谁来负责“最后关门”释放内存就成了一个令人头疼的所有权问题。这就是std::shared_ptr共享智能指针登场的背景。它不是C11才引入的新鲜玩意儿但绝对是现代C工程实践中使用频率最高、也最值得深入理解的智能指针之一。简单说shared_ptr通过引用计数机制实现了对动态分配对象的多所有权管理。当最后一个持有该对象的shared_ptr被销毁时它所管理的对象才会被自动删除。这听起来很美好但它绝不是“银弹”。滥用shared_ptr同样会带来循环引用、性能开销等新问题。这篇文章我们就来彻底拆解std::shared_ptr。我不会只停留在API用法的罗列上那样看手册就行。我会结合我十多年踩坑填坑的经验从它的核心设计原理、内部实现机制讲起再到各种实战场景下的正确用法、经典误区和性能调优技巧。无论你是正在准备面试被“智能指针的引用计数是不是线程安全的”这种问题困扰还是在实际项目中遇到了对象生命周期管理的难题相信这篇近万字的深度解析都能给你带来实实在在的帮助。2. 共享智能指针的核心原理与内部实现拆解要用好一个工具首先得理解它到底是怎么工作的。std::shared_ptr的神秘面纱之下核心就是引用计数。2.1 引用计数机制深度剖析你可以把shared_ptr想象成一个“智能的包裹”。这个包裹里至少包含两个部分原始指针Raw Pointer指向我们真正关心的、在堆上分配的那个对象。控制块Control Block一个在堆上单独分配的小数据结构它至少包含引用计数Use Count记录当前有多少个shared_ptr正指向这个对象。弱引用计数Weak Count记录有多少个weak_ptr在观察这个对象这个我们后面会详谈。删除器Deleter一个可调用对象负责在引用计数归零时如何销毁对象并释放内存。默认就是delete操作符。分配器Allocator用于分配控制块本身的内存通常使用默认的。当我们创建一个shared_ptr时如果是从原始指针构造例如std::shared_ptrFoo sp1(new Foo)它会在堆上同时创建控制块和对象本身。之后当我们通过拷贝构造函数或赋值运算符让另一个shared_ptrsp2也指向同一个对象时sp2不会复制对象而是复制指向同一个控制块的指针并将控制块内的引用计数加1。#include iostream #include memory class MyClass { public: MyClass() { std::cout MyClass 构造函数\n; } ~MyClass() { std::cout MyClass 析构函数\n; } }; int main() { std::cout 创建 sp1:\n; std::shared_ptrMyClass sp1(new MyClass); // 引用计数 1 { std::cout 进入内部作用域创建 sp2 (拷贝自 sp1):\n; std::shared_ptrMyClass sp2 sp1; // 引用计数 2 std::cout sp1.use_count() sp1.use_count() \n; // 输出 2 std::cout sp2.use_count() sp2.use_count() \n; // 输出 2 std::cout 离开内部作用域sp2 将被销毁:\n; } // sp2 析构引用计数减为 1 std::cout sp1.use_count() sp1.use_count() \n; // 输出 1 std::cout main 函数结束sp1 将被销毁:\n; return 0; } // sp1 析构引用计数归零调用 MyClass 的析构函数并释放内存这段代码的运行结果会清晰地展示引用计数的变化和对象生命周期的精确控制。理解这个机制是理解后续所有高级用法和陷阱的基础。2.2 控制块的生命周期与创建时机这里有一个至关重要的细节直接关系到程序的正确性控制块何时被创建核心规则一个被shared_ptr管理的对象有且仅有一个控制块与之关联。违反这条规则会导致多个控制块各自为政引用计数混乱最终极有可能造成对象被多次释放双重释放引发未定义行为通常是程序崩溃。以下几种操作会创建新的控制块使用原始指针构造std::shared_ptrT p(new T)。使用std::make_shared推荐auto p std::make_sharedT()。使用std::allocate_shared。以下几种操作会共享已有的控制块引用计数增加拷贝构造std::shared_ptrT q(p)。拷贝赋值q p。从另一个shared_ptr构造。致命的错误示范int* raw_ptr new int(42); std::shared_ptrint sp1(raw_ptr); std::shared_ptrint sp2(raw_ptr); // 灾难为同一个 raw_ptr 创建了第二个控制块。 // 当 sp1 和 sp2 各自销毁时它们都会尝试 delete raw_ptr导致双重释放。正确的做法永远不要将同一个原始指针交给多个shared_ptr构造函数。如果需要共享始终通过拷贝已有的shared_ptr来实现。2.3std::make_shared的优势与内部优化在C11之后创建shared_ptr的首选方式不再是直接new而是使用std::make_shared。// 传统方式不推荐 std::shared_ptrWidget spw1(new Widget); // 现代方式推荐 auto spw2 std::make_sharedWidget();make_shared不仅仅是语法糖它带来了两大核心优势异常安全考虑函数调用processWidget(std::shared_ptrWidget(new Widget), computePriority())。C并未规定函数参数求值顺序。如果执行顺序是new Widget-computePriority()可能抛出异常- 构造shared_ptr。那么当computePriority抛出异常时new Widget分配的内存将无法被释放因为负责管理它的shared_ptr还未构造出来这就发生了内存泄漏。使用make_shared可以保证对象的分配和shared_ptr控制块的构造是原子的避免了这种危险间隙。性能提升make_shared通常通过一次内存分配同时为对象本身和控制块分配一块连续的内存。而分开的new和shared_ptr构造需要两次分配。这不仅减少了内存分配器的调用开销还提高了内存的局部性可能带来缓存性能的提升。当然make_shared也有其局限性比如无法指定自定义删除器或分配器对象和控制块内存绑定导致延迟释放等这些我们会在后面的“注意事项”中详细讨论。3. 共享智能指针的实战应用与高级特性掌握了原理我们来看看shared_ptr在实战中如何大显身手以及它那些容易被忽略的高级特性。3.1 在容器与数据结构中的使用shared_ptr是STL容器的完美搭档用于管理动态生命周期的元素集合。#include vector #include memory #include iostream class Sensor { public: Sensor(int id) : id_(id) {} void read() { std::cout Sensor id_ reading...\n; } private: int id_; }; int main() { std::vectorstd::shared_ptrSensor sensorNetwork; // 动态创建传感器并加入网络 for (int i 0; i 5; i) { sensorNetwork.push_back(std::make_sharedSensor(i)); } // 某个传感器可能被另一个子系统引用 std::shared_ptrSensor importantSensor sensorNetwork[2]; // 即使从vector中移除只要importantSensor还存在该传感器对象就不会被销毁 sensorNetwork.erase(sensorNetwork.begin() 2); importantSensor-read(); // 仍然有效 // 清空vector其他传感器引用计数归零被自动销毁 sensorNetwork.clear(); // 此时只有 importantSensor 还活着 return 0; } // importantSensor 销毁最后一个传感器对象被释放这种用法在GUI编程管理窗口部件、游戏开发管理游戏实体、网络服务管理连接会话中非常常见。它优雅地解决了容器元素所有权转移和共享的问题。3.2 自定义删除器Deleter默认情况下shared_ptr使用delete来销毁对象。但并非所有资源都是用new分配的或者需要特殊的清理逻辑。这时就需要自定义删除器。#include memory #include iostream #include cstdio // 1. 用于 FILE* 资源 void file_deleter(FILE* fp) { if (fp) { std::cout Closing file...\n; std::fclose(fp); } } // 2. 用于数组不推荐优先使用std::vector或std::array struct array_deleter { void operator()(int* p) { std::cout Deleting array...\n; delete[] p; } }; // 3. Lambda表达式作为删除器 auto lambda_deleter [](Connection* conn) { std::cout Disconnecting...\n; conn-disconnect(); delete conn; }; int main() { // 使用自定义删除器管理文件句柄 std::shared_ptrFILE spFile(std::fopen(test.txt, r), file_deleter); if (spFile) { // 使用 spFile.get() 获取原始 FILE* 进行读写 } // 离开作用域自动调用 file_deleter 关闭文件 // 管理动态数组注意shared_ptrT[] 在C17才支持此处是变通 std::shared_ptrint spArray(new int[10], array_deleter()); // 使用Lambda管理自定义资源 std::shared_ptrConnection spConn(new Connection, lambda_deleter); return 0; }重要提示自定义删除器是shared_ptr类型的一部分吗不是删除器是shared_ptr对象的组成部分但不是其模板参数的一部分。这意味着两个拥有不同删除器的shared_ptrT仍然是相同类型可以互相赋值、放入同一容器。删除器的类型信息存储在控制块中。3.3std::enable_shared_from_this解决“从this创建shared_ptr”的困境这是一个经典陷阱。假设你有一个对象它被shared_ptr管理着。在这个对象的成员函数内部你需要传递一个指向自己的shared_ptr给其他函数比如注册回调。你可能会想当然地写class BadWidget { public: void process() { // 错误这会为 *this 创建一个全新的控制块。 std::shared_ptrBadWidget spThis(this); someRegistry.registerCallback(spThis); // 危险 } }; auto widget std::make_sharedBadWidget(); widget-process(); // 灾难widget 和 spThis 各有一个控制块导致双重释放。为了解决这个问题标准库提供了std::enable_shared_from_this这个混入mixin基类。#include memory #include iostream class GoodWidget : public std::enable_shared_from_thisGoodWidget { public: GoodWidget() { std::cout GoodWidget constructed\n; } ~GoodWidget() { std::cout GoodWidget destroyed\n; } std::shared_ptrGoodWidget getShared() { // 正确返回一个与现有控制块共享的 shared_ptr return shared_from_this(); } void process() { auto spThis shared_from_this(); std::cout use_count in process: spThis.use_count() \n; // 安全地传递 spThis } }; int main() { auto sp1 std::make_sharedGoodWidget(); { auto sp2 sp1-getShared(); // 引用计数变为2 sp2-process(); // 内部使用 shared_from_this() } // sp2 销毁引用计数变回1 return 0; } // sp1 销毁引用计数归零对象析构使用enable_shared_from_this的硬性条件对象必须已经被一个shared_ptr所管理即已存在控制块才能调用shared_from_this()。在构造函数中调用是未定义行为因为此时对象尚未被交给shared_ptr。通常的解决模式是在工厂函数中创建对象并立即用shared_ptr包装它。4. 共享智能指针的线程安全性与性能考量shared_ptr的线程安全是一个面试高频考点也是一个容易误解的地方。4.1 引用计数的原子操作标准规定shared_ptr的引用计数操作是原子的。这意味着在多线程环境下多个线程同时拷贝或销毁指向同一对象的shared_ptr引用计数的增减是线程安全的不会导致计数错误或内存泄漏。控制块本身通常使用原子操作如std::atomic来实现这一点。但是这绝不意味着shared_ptr管理的对象本身是线程安全的。std::shared_ptrBankAccount account std::make_sharedBankAccount(1000); // 线程A void threadA() { auto localCopy account; // 安全的引用计数递增 localCopy-deposit(500); // 危险对 BankAccount 对象的非原子操作 } // 线程B void threadB() { auto localCopy account; // 安全的引用计数递增 localCopy-withdraw(300); // 危险数据竞争 }上面的代码中account这个shared_ptr变量本身的读写可能也不是线程安全的如果多个线程同时执行account newAccount。更关键的是deposit和withdraw操作在BankAccount对象内部如果没有同步机制如互斥锁就会导致数据竞争。shared_ptr只保证了控制块主要是引用计数的线程安全不保证其所指对象的线程安全也不保证shared_ptr实例本身作为一个包含两个指针的胖指针的拷贝赋值是原子的。线程安全黄金法则多个线程同时读取同一个shared_ptr对象是安全的。多个线程对不同的shared_ptr实例进行拷贝、赋值、重置reset是安全的因为它们操作不同的控制块或增加同一控制块的引用计数这是原子的。多个线程对同一个shared_ptr实例进行写操作如reset或赋值是不安全的需要外部同步例如用std::atomicstd::shared_ptrT这是C20提供的特性或使用互斥锁。无论shared_ptr如何对所管理对象的访问必须由用户自己保证线程安全。4.2 性能开销分析与使用建议shared_ptr不是零成本的抽象它的开销主要来自内存开销每个shared_ptr对象本身通常占两个指针的大小一个指向对象一个指向控制块。控制块本身也包含引用计数、弱引用计数、删除器、分配器等有额外的内存占用。使用make_shared可以合并对象和控制块的内存分配减少一些开销。时间开销每次拷贝构造、赋值、析构都需要对引用计数进行原子操作递增或递减。原子操作比普通整数操作慢得多。在引用计数归零时需要调用删除器并释放内存。性能优化建议优先传递const std::shared_ptr如果函数只需要借用shared_ptr来访问对象并且不涉及所有权的共享即不需要延长对象生命周期那么应该传递常量引用避免不必要的引用计数原子操作。void goodFunc(const std::shared_ptrBigObject obj) { // 好无计数操作 obj-doSomething(); } void badFunc(std::shared_ptrBigObject obj) { // 不好触发拷贝计数递增递减 obj-doSomething(); }考虑使用std::weak_ptr打破循环引用见下文避免对象因循环引用而永远无法释放。在性能关键的循环或数据结构中评估是否真的需要共享所有权。有时独占所有权的std::unique_ptr或甚至直接使用对象可能更合适。5. 共享智能指针的经典陷阱与避坑指南即使是有经验的开发者也容易在shared_ptr的使用上栽跟头。下面是我总结的几个最常见、最危险的陷阱。5.1 循环引用内存泄漏的隐形杀手这是shared_ptr最著名的问题。当两个或多个对象通过shared_ptr互相引用时就会形成循环引用导致引用计数永远无法降为零对象无法被释放。#include memory #include iostream class Node { public: std::shared_ptrNode partner; ~Node() { std::cout Node destroyed\n; } }; int main() { auto nodeA std::make_sharedNode(); auto nodeB std::make_sharedNode(); nodeA-partner nodeB; // A 引用 BB的引用计数2 (nodeB 和 nodeA-partner) nodeB-partner nodeA; // B 引用 AA的引用计数2 (nodeA 和 nodeB-partner) std::cout A use_count: nodeA.use_count() \n; // 输出 2 std::cout B use_count: nodeB.use_count() \n; // 输出 2 return 0; } // 离开作用域nodeA 和 nodeB 的局部变量被销毁。 // 但此时 A 的引用计数从2减为1还剩 B-partner 指着它 // B 的引用计数从2减为1还剩 A-partner 指着它 // 引用计数都不为0因此 A 和 B 对象均不会被销毁内存泄漏解决方案使用std::weak_ptr。weak_ptr是一种“弱引用”它指向一个由shared_ptr管理的对象但不增加其引用计数。它用于解决循环引用和作为缓存观察者。class NodeSafe { public: std::weak_ptrNodeSafe partner; // 使用 weak_ptr 代替 shared_ptr ~NodeSafe() { std::cout NodeSafe destroyed\n; } void checkPartner() { if (auto sp partner.lock()) { // 尝试将 weak_ptr 提升为 shared_ptr std::cout Partner is still alive.\n; } else { std::cout Partner has been destroyed.\n; } } }; int main() { auto nodeA std::make_sharedNodeSafe(); auto nodeB std::make_sharedNodeSafe(); nodeA-partner nodeB; // B 的引用计数仍为1 (只有 nodeB) nodeB-partner nodeA; // A 的引用计数仍为1 (只有 nodeA) return 0; } // nodeA, nodeB 销毁引用计数归零对象被正确释放。weak_ptr需要通过lock()成员函数来获取一个临时的shared_ptr以访问对象。如果对象还存在lock()返回一个有效的shared_ptr并增加引用计数如果对象已被释放则返回一个空的shared_ptr。5.2 避免从原始指针多次构造如前所述这是导致双重释放的致命错误。务必牢记一个对象一个控制块。传递所有权时始终传递shared_ptr本身而不是其底层的原始指针通过get()获得。5.3shared_ptr与this指针的陷阱我们已经用enable_shared_from_this解决了在成员函数内获取shared_ptr的问题。但还有一个相关陷阱在类的析构函数中调用shared_from_this()同样是未定义行为因为此时对象的部分可能已经被销毁引用计数处于不稳定状态。5.4 慎用get()返回的原始指针sp.get()返回的是托管对象的原始指针。你必须极度小心地使用它不要用它创建新的shared_ptr原因同上。不要delete它shared_ptr会做。确保在shared_ptr的生命周期内使用它否则可能访问已释放的内存。在多线程环境下即使你持有原始指针也不能保证对象存活因为另一个线程可能让最后一个shared_ptr析构。6.shared_ptr与unique_ptr的选择策略C11提供了两大智能指针shared_ptr共享所有权和unique_ptr独占所有权。如何选择选择std::unique_ptr当所有权是独占的、清晰的、可转移的。例如工厂函数返回一个资源。你追求零开销或最小开销unique_ptr通常大小等同于原始指针无控制块开销。你需要自定义删除器且删除器是类型的一部分可能带来尺寸变化但有时可用于空基类优化。选择std::shared_ptr当所有权需要被多个实体共享且这些实体的生命周期不确定。你需要将指针存入标准容器并且容器中的元素可能被多个地方引用。你需要建立复杂的对象图如观察者模式、缓存并且可能涉及循环引用需配合weak_ptr。一个实用的经验法则默认使用unique_ptr除非你明确需要共享所有权。shared_ptr的共享语义和引用计数开销是实实在在的不应该作为默认选择。清晰的独占所有权能使代码更容易理解和维护。7. 实战构建一个简单的基于shared_ptr和weak_ptr的缓存系统让我们用一个综合例子来结束。假设我们要实现一个简单的“用户信息”缓存当内存紧张或用户长时间不访问时缓存项可以自动失效但外部持有shared_ptr时又能保证对象存活。#include memory #include unordered_map #include string #include iostream #include mutex class UserProfile { public: UserProfile(const std::string id, const std::string name) : userId(id), userName(name) { std::cout UserProfile [ userId ] loaded.\n; } ~UserProfile() { std::cout UserProfile [ userId ] unloaded.\n; } void access() const { std::cout Accessing profile of userName ( userId )\n; } private: std::string userId; std::string userName; }; class UserCache { public: // 获取用户信息如果缓存不存在则加载 std::shared_ptrUserProfile getUser(const std::string userId) { std::lock_guardstd::mutex lock(cacheMutex_); auto it cache_.find(userId); if (it ! cache_.end()) { // 找到 weak_ptr尝试提升 if (auto sp it-second.lock()) { std::cout Cache hit for userId .\n; return sp; // 提升成功返回 shared_ptr } else { // weak_ptr 已过期对象已被释放从缓存中移除无效项 std::cout Cache entry expired for userId , removing.\n; cache_.erase(it); } } // 缓存未命中或已过期加载新数据 std::cout Cache miss for userId , loading...\n; auto sp std::make_sharedUserProfile(userId, User_ userId); cache_[userId] sp; // 存储 weak_ptr return sp; } // 清理所有已过期的缓存项 void cleanupExpired() { std::lock_guardstd::mutex lock(cacheMutex_); for (auto it cache_.begin(); it ! cache_.end(); ) { if (it-second.expired()) { std::cout Cleaning up expired entry: it-first \n; it cache_.erase(it); } else { it; } } } private: std::unordered_mapstd::string, std::weak_ptrUserProfile cache_; std::mutex cacheMutex_; // 保证线程安全 }; int main() { UserCache cache; auto user1 cache.getUser(001); // 加载 User_001 { auto user1_again cache.getUser(001); // 缓存命中引用计数增加 user1-access(); user1_again-access(); } // user1_again 销毁引用计数减少 auto user2 cache.getUser(002); // 加载 User_002 // 模拟外部不再持有 user1 和 user2 user1.reset(); user2.reset(); // 此时缓存中 weak_ptr 指向的对象可能已被释放如果没有其他 shared_ptr 持有 cache.cleanupExpired(); // 会清理过期的条目 // 再次请求 user1需要重新加载 auto user1_reloaded cache.getUser(001); return 0; }这个例子展示了shared_ptr和weak_ptr的经典组合缓存持有weak_ptr不阻止用户对象被释放。当内存不足或用户长时间不活跃时只要外部没有shared_ptr持有该对象它就会被自动回收。客户端通过getUser获得shared_ptr在访问期间保证了对象的存活。lock()和expired()用于安全地检查对象状态并提升引用。这种模式在资源管理、缓存实现、观察者模式中非常有用它很好地平衡了资源生命周期和访问需求。理解并熟练运用shared_ptr和weak_ptr你的C资源管理功力会上一个大台阶。记住智能指针是工具理解其原理和边界才能让它为你所用而不是引入新的问题。

相关新闻

YOLO目标检测在肺部CT影像分析中的优化与应用

YOLO目标检测在肺部CT影像分析中的优化与应用

1. 肺部CT数据集在YOLO目标检测中的应用价值肺部CT影像的计算机辅助诊断一直是医疗AI领域的热点研究方向。传统的人工阅片方式存在效率低、主观性强等问题,而基于深度学习的自动检测技术能够显著提升诊断效率和一致性。在众多目标检测算法中,YOLO(You On…

2026/8/19 0:20:34 阅读更多 →
C++实战:从零构建足球管理系统,掌握面向对象与数据持久化

C++实战:从零构建足球管理系统,掌握面向对象与数据持久化

1. 项目概述:为什么需要一个足球管理系统? 如果你是一个足球俱乐部的管理者、青训教练,或者只是一个狂热的足球爱好者,想要用技术手段来管理球队的日常,那么“足球管理系统”这个概念你一定不陌生。它本质上是一个信息…

2026/8/21 2:25:09 阅读更多 →
C++实现债券折扣曲线拟合:量化金融核心定价引擎构建指南

C++实现债券折扣曲线拟合:量化金融核心定价引擎构建指南

1. 项目概述:从量化视角看债券定价的“尺子”在金融工程和固定收益分析领域,债券折扣曲线(Discount Curve)是绝对的核心基础设施。你可以把它想象成一把衡量未来现金流价值的“尺子”。无论是给一只简单的国债定价,还是…

2026/8/21 5:11:07 阅读更多 →

最新新闻

red_team_attack_lab 全景图:15 台 Windows 域主机攻击拓扑与完整攻击面地图

red_team_attack_lab 全景图:15 台 Windows 域主机攻击拓扑与完整攻击面地图

red_team_attack_lab 全景图:15 台 Windows 域主机攻击拓扑与完整攻击面地图 【免费下载链接】red_team_attack_lab Red Team Attack Lab for TTP testing & research 项目地址: https://gitcode.com/gh_mirrors/re/red_team_attack_lab red_team_attack…

2026/8/22 16:04:28 阅读更多 →
formik-antd从v1升级到v2:Ant Design 3迁移Ant Design 4的实用清单

formik-antd从v1升级到v2:Ant Design 3迁移Ant Design 4的实用清单

formik-antd从v1升级到v2:Ant Design 3迁移Ant Design 4的实用清单 【免费下载链接】formik-antd Simple declarative bindings for Ant Design and Formik. 项目地址: https://gitcode.com/gh_mirrors/fo/formik-antd formik-antd 是一个为 Ant Design 和 F…

2026/8/22 16:04:28 阅读更多 →
Marketch:3步装好的Sketch插件,尺寸和CSS随点随取

Marketch:3步装好的Sketch插件,尺寸和CSS随点随取

Marketch:3步装好的Sketch插件,尺寸和CSS随点随取 【免费下载链接】marketch Marketch is a Sketch 3 plug-in for automatically generating html page that can measure and get CSS styles on it. 项目地址: https://gitcode.com/gh_mirrors/ma/mar…

2026/8/22 16:04:28 阅读更多 →
逆向 APK 的瑞士军刀:Apktool 从解码到重建的实用指南

逆向 APK 的瑞士军刀:Apktool 从解码到重建的实用指南

逆向 APK 的瑞士军刀:Apktool 从解码到重建的实用指南 【免费下载链接】Apktool A tool for reverse engineering Android apk files 项目地址: https://gitcode.com/GitHub_Trending/ap/Apktool Apktool 是一款用于逆向 Android APK 的开源命令行工具&#…

2026/8/22 16:04:28 阅读更多 →
[光学原理与应用-507]:光为什么会有偏振?从哲学的角度阐述

[光学原理与应用-507]:光为什么会有偏振?从哲学的角度阐述

光偏振:哲学视角的解读物理事实作为根基:光是横电磁波,传播方向与电场振动方向互相正交;振动被约束在垂直行进方向的二维平面之内,这是偏振的物质基础。哲学不是推翻物理定律,而是对这一现象背后蕴含的存在…

2026/8/22 16:04:28 阅读更多 →
香港电讯荣获“新能源与物联网数字转型解决方案创新奖”

香港电讯荣获“新能源与物联网数字转型解决方案创新奖”

“第五届高端制造业暨新能源CIO论坛”于8月29日在上海举行,汇集了近300位智能制造行业的知名企业高管、CIO、IT负责人以及信息化服务商出席。香港电讯凭借多年来在制造业及新能源领域的服务经验,受邀参与活动,并荣获“新能源与物联网数字转型…

2026/8/22 16:03:28 阅读更多 →

日新闻

沉金PCB工艺实战指南:从设计到SMT焊接的可靠性保障

沉金PCB工艺实战指南:从设计到SMT焊接的可靠性保障

在电子硬件开发领域,PCB(印制电路板)的沉金工艺是提升产品可靠性和焊接质量的关键环节。对于需要高密度互连、长期稳定运行或高频信号传输的板卡,如“黍姐仿通行证”这类可能涉及身份识别、数据交互的硬件项目,选择正确…

2026/8/22 0:00:11 阅读更多 →
电气考研电路八月强化四步法:从知识体系到真题实战的闭环攻略

电气考研电路八月强化四步法:从知识体系到真题实战的闭环攻略

这次我们来看一个针对电气考研电路科目的学习规划项目。它不是软件工具,而是一套聚焦于8月份关键节点的备考策略。对于电气工程考研的同学来说,电路分析是专业课的重中之重,也是拉开分差的关键。进入8月,复习进入强化阶段&#xf…

2026/8/22 0:00:11 阅读更多 →
消除AI代码的“AI味”:Claude Code设计优化技能配置与实战指南

消除AI代码的“AI味”:Claude Code设计优化技能配置与实战指南

大家好,我是专注于前端开发与AI工具实践的技术博主。在日常使用 Claude Code 等AI编程助手时,你是否也遇到过这样的困扰:生成的代码功能上没问题,但代码风格、组件设计、交互逻辑总透着一股“AI味”——布局单调、样式简陋、交互生…

2026/8/22 0:00:11 阅读更多 →

周新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者,最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent,从本地部署到云端API,我们正处在一个技术栈快速重构的节点。然而,面对层出不穷的模型、框架和工具&#xf…

2026/8/21 3:21:33 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/22 8:09:09 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…

2026/8/21 6:07:56 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/21 16:42:28 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/22 7:31:03 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/22 3:22:48 阅读更多 →