电商数据采集合规指南与Python爬虫实践
2026/8/9 20:32:47
好的,这是一个关于 C++ 智能指针的全面指南:
new/delete)易导致的内存泄漏、重复释放等问题。标准库在<memory>头文件中提供了三种主要的智能指针:
std::unique_ptr(独占所有权)unique_ptr可以指向一个给定的对象。它不能被复制。std::move进行所有权转移。#include <memory> #include <iostream> class MyClass { public: MyClass() { std::cout << "MyClass constructed\n"; } ~MyClass() { std::cout << "MyClass destroyed\n"; } void doSomething() { std::cout << "Doing something\n"; } }; int main() { // 创建并拥有一个 MyClass 对象 std::unique_ptr<MyClass> ptr1(new MyClass()); ptr1->doSomething(); // 所有权转移 (ptr1 变为 nullptr) std::unique_ptr<MyClass> ptr2 = std::move(ptr1); if (!ptr1) { std::cout << "ptr1 is now empty\n"; } ptr2->doSomething(); // 使用 make_unique (C++14 起推荐) auto ptr3 = std::make_unique<MyClass>(); ptr3->doSomething(); // ptr3 离开作用域,自动销毁其管理的对象 return 0; }auto FileDeleter = [](FILE* fp) { if (fp) fclose(fp); }; std::unique_ptr<FILE, decltype(FileDeleter)> filePtr(fopen("data.txt", "r"), FileDeleter);std::shared_ptr(共享所有权)shared_ptr可以指向同一个对象。shared_ptr指向该对象时,计数器增加;当shared_ptr析构时,计数器减少。计数器归零时,自动删除对象。#include <memory> #include <iostream> class MyResource { public: MyResource() { std::cout << "Resource created\n"; } ~MyResource() { std::cout << "Resource destroyed\n"; } }; int main() { // 创建共享对象 (推荐使用 make_shared) std::shared_ptr<MyResource> sharedPtr1 = std::make_shared<MyResource>(); { // 共享所有权 (引用计数 +1) std::shared_ptr<MyResource> sharedPtr2 = sharedPtr1; std::cout << "Use count inside inner scope: " << sharedPtr2.use_count() << "\n"; // 输出 2 } // sharedPtr2 析构,引用计数 -1 std::cout << "Use count outside inner scope: " << sharedPtr1.use_count() << "\n"; // 输出 1 // sharedPtr1 离开作用域,引用计数归零,对象销毁 return 0; }shared_ptr需要额外的内存存储引用计数和控制信息。make_shared通常能优化此开销。shared_ptr,这会导致多个控制块和双重释放。std::weak_ptr(弱引用)weak_ptr指向一个由shared_ptr管理的对象,但不增加其引用计数。shared_ptr创建或赋值。要访问对象,需先尝试将其提升 (lock) 为shared_ptr。#include <memory> #include <iostream> class MyResource; class Observer { public: void observe(std::shared_ptr<MyResource> res) { weakResource = res; // 用 shared_ptr 初始化 weak_ptr } void tryAccess() { auto sharedRes = weakResource.lock(); // 尝试提升为 shared_ptr if (sharedRes) { std::cout << "Resource is still alive, accessing it.\n"; } else { std::cout << "Resource has been destroyed.\n"; } } private: std::weak_ptr<MyResource> weakResource; }; class MyResource { public: MyResource() { std::cout << "Resource created\n"; } ~MyResource() { std::cout << "Resource destroyed\n"; } }; int main() { auto resource = std::make_shared<MyResource>(); Observer obs; obs.observe(resource); obs.tryAccess(); // 输出 Resource is still alive... resource.reset(); // 销毁 resource obs.tryAccess(); // 输出 Resource has been destroyed. return 0; }shared_ptr相互持有对方,导致它们的引用计数永远无法归零,从而发生内存泄漏。class Node { public: std::shared_ptr<Node> next; // 指向下一个节点 std::shared_ptr<Node> prev; // 指向上一个节点 (导致循环引用) Node() { std::cout << "Node created\n"; } ~Node() { std::cout << "Node destroyed\n"; } }; int main() { auto node1 = std::make_shared<Node>(); auto node2 = std::make_shared<Node>(); node1->next = node2; // node1 持有 node2 node2->prev = node1; // node2 持有 node1 (循环引用!) // node1 和 node2 离开作用域,但它们的引用计数都是 1 (彼此持有),对象不会被销毁! return 0; // 输出: Node created\nNode created\n (没有销毁信息) }weak_ptr打破循环class Node { public: std::shared_ptr<Node> next; std::weak_ptr<Node> prev; // 将其中一个指针改为 weak_ptr Node() { std::cout << "Node created\n"; } ~Node() { std::cout << "Node destroyed\n"; } }; int main() { auto node1 = std::make_shared<Node>(); auto node2 = std::make_shared<Node>(); node1->next = node2; node2->prev = node1; // node2 持有 node1 的弱引用 // 现在 node1 引用计数 = 1 (仅被 main 持有), node2 引用计数 = 2 (被 main 和 node1 持有) // 离开作用域: // main 释放 node1 -> node1 引用计数归零,销毁 node1 (释放 node1->next 会减少 node2 引用计数到 1) // main 释放 node2 -> node2 引用计数归零,销毁 node2 return 0; // 输出: Node created\nNode created\nNode destroyed\nNode destroyed }new/delete。unique_ptr:除非需要共享所有权。make_unique和make_shared:更安全、更高效。shared_ptr:注意控制块开销和潜在的循环引用。weak_ptr:解决循环引用问题和作为观察者。shared_ptr的引用计数是线程安全的,但对象本身的操作可能需要额外的同步。遵循这些原则和实践,可以显著提高 C++ 程序的内存安全性和可维护性。