shared_ptr实际场景咨询:为何需多所有权而非用unique_ptr
嘿,我完全懂你这种感觉——刚接触智能指针的时候,总觉得unique_ptr好像能包打天下,直到遇到那种**多个地方都需要访问同一个对象,而且谁都不是唯一的‘主人’**的场景。我给你举个非常真实的例子:支持多窗口/多标签页的文本编辑器,这绝对是shared_ptr的主场,用unique_ptr根本搞不定。
场景说明
假设你正在开发一个轻量文本编辑器,用户可以打开同一个文档的多个窗口(比如分屏对比内容,或者在不同标签页编辑同一文档)。每个窗口(我们叫它DocumentView)都需要读取和修改文档内容,而且文档的生命周期应该是:只要还有一个窗口在显示它,文档就不能被销毁;当所有窗口都关闭后,文档才自动释放内存。
这时候unique_ptr就歇菜了——因为unique_ptr强调“唯一所有权”,你没法把同一个unique_ptr交给多个DocumentView,赋值或者传递都会转移所有权,导致其他视图拿到的是悬空指针。而shared_ptr的引用计数机制正好完美匹配这个需求:每个视图持有一个shared_ptr<Document>,每次创建新视图计数+1,销毁视图计数-1,当计数降到0时,Document自动被销毁。
实用代码示例
#include <iostream> #include <memory> #include <vector> #include <string> // 文档类:存储文本内容的核心业务对象 class Document { private: std::string content; public: Document(const std::string& initial_content) : content(initial_content) { std::cout << "Document 被创建了!" << std::endl; } ~Document() { std::cout << "Document 被销毁了!" << std::endl; } // 修改文档内容 void append_content(const std::string& text) { content += text; } // 获取文档内容 const std::string& get_content() const { return content; } }; // 文档视图类:代表一个显示/编辑文档的窗口 class DocumentView { private: std::shared_ptr<Document> doc; // 持有文档的共享所有权 std::string view_name; public: DocumentView(std::shared_ptr<Document> document, const std::string& name) : doc(std::move(document)), view_name(name) { std::cout << "视图 [" << view_name << "] 已创建,当前文档引用计数:" << doc.use_count() << std::endl; } ~DocumentView() { std::cout << "视图 [" << view_name << "] 被销毁,当前文档引用计数:" << doc.use_count() - 1 << std::endl; } // 在当前视图中编辑文档 void edit_document(const std::string& text) { doc->append_content(text); std::cout << "视图 [" << view_name << "] 编辑后文档内容:\n" << doc->get_content() << std::endl; } }; int main() { // 创建一个文档,用shared_ptr管理其生命周期 auto doc = std::make_shared<Document>("初始文档内容\n"); // 创建多个视图,共享同一个文档 std::vector<std::unique_ptr<DocumentView>> views; views.emplace_back(std::make_unique<DocumentView>(doc, "主窗口")); views.emplace_back(std::make_unique<DocumentView>(doc, "分屏窗口1")); views.emplace_back(std::make_unique<DocumentView>(doc, "分屏窗口2")); // 用任意一个视图编辑文档,所有视图都会看到更新 views[1]->edit_document("分屏窗口1添加的内容\n"); // 关闭第一个视图(销毁对应的DocumentView对象) views.erase(views.begin()); // 用剩下的第三个视图继续编辑 views[1]->edit_document("分屏窗口2添加的内容\n"); // 程序结束时,所有视图被销毁,文档最后自动销毁 return 0; }
为什么这是最优选择
这个场景里,shared_ptr是唯一合适的智能指针:
- 用
unique_ptr的话,你只能让一个视图拥有文档所有权,其他视图只能用裸指针,这会导致悬空指针的风险(比如拥有所有权的视图被销毁了,其他视图还在访问文档)。 - 用裸指针的话,你需要手动跟踪所有引用文档的视图,在最后一个视图关闭时手动delete文档,这很容易出错(比如漏跟踪导致内存泄漏,或者重复释放)。
shared_ptr的引用计数机制自动帮我们处理了这些问题,代码简洁且安全,完全贴合“多个所有者共享对象”的真实业务需求。
内容的提问来源于stack exchange,提问作者code
相关产品推荐
相关产品推荐

