osg学习(三)osg::Observer的作用

博客提到本意是存放所有观察者,但在observer_ptr中未看到其何时起作用,围绕信息技术领域中observer_ptr的作用时机展开疑问探讨。

本意可能是要存放所有观察者,但是在observer_ptr中没有看到什么时候起作用。

 

 

 

 

 

`osg::ref_ptr` 是 **OpenSceneGraph (OSG)** 库中的智能指针类,用于**自动管理 OSG 对象的生命周期**,避免内存泄漏和悬空指针问题。它通过引用计数机制跟踪对象的引用次数,当最后一个 `ref_ptr` 被销毁时,自动释放所管理的对象。 --- ### **1. 核心特性** #### **(1) 引用计数机制** - 每个 OSG 对象(如 `osg::Node`、`osg::Geometry`)继承自 `osg::Referenced`,内部维护一个引用计数器。 - `ref_ptr` 在构造、赋值或复制时增加引用计数,析构时减少计数。当计数归零时,对象自动删除。 #### **(2) 线程安全** - OSG 的引用计数操作是**原子性**的,支持多线程环境下的安全使用。 #### **(3) 与裸指针的兼容性** - 可以通过 `get()` 获取裸指针,但需谨慎避免手动删除。 - 支持隐式转换为 `bool`,便于检查指针有效性。 --- ### **2. 基本用法** #### **(1) 构造与赋值** ```cpp #include <osg/ref_ptr> #include <osg/Node> int main() { // 创建一个 ref_ptr 管理的 Node 对象 osg::ref_ptr<osg::Node> node1 = new osg::Node; // 通过 make_ref 辅助函数(C++11 风格) auto node2 = osg::make_ref<osg::Node>(); // 赋值另一个 ref_ptr osg::ref_ptr<osg::Node> node3 = node1; // 引用计数变化:node1、node2、node3 的计数均为 1(独立对象) return 0; } ``` #### **(2) 访问对象** ```cpp osg::ref_ptr<osg::Node> node = new osg::Node; node->setName("MyNode"); // 通过 -> 操作符访问成员 osg::Node* rawPtr = node.get(); // 获取裸指针(不推荐长期持有) if (node) { // 检查是否非空 std::cout << "Node name: " << node->getName() << std::endl; } ``` #### **(3) 释放对象** ```cpp node = nullptr; // 显式释放引用,引用计数减 1 // 若计数归零,对象自动删除 ``` --- ### **3. 关键方法** | 方法 | 功能 | |------|------| | `ref()` | 增加引用计数(通常由 `ref_ptr` 自动调用) | | `unref()` | 减少引用计数,计数归零时删除对象 | | `get()` | 返回裸指针(不改变引用计数) | | `release()` | 释放所有权,返回裸指针但不减少计数 | | `valid()` | 检查指针是否非空(等价于 `operator bool`) | --- ### **4. 与 `std::shared_ptr` 的对比** | 特性 | `osg::ref_ptr` | `std::shared_ptr` | |------|----------------|------------------| | **用途** | 专为 OSG 对象设计 | 通用智能指针 | | **引用计数** | 原子操作,线程安全 | 原子操作,线程安全 | | **自定义删除器** | 不支持 | 支持 | | **性能** | 针对 OSG 优化 | 通用但稍重 | | **兼容性** | 仅限 OSG 对象 | 任意类型 | --- ### **5. 常见问题与最佳实践** #### **(1) 循环引用问题** - **问题**:若两个对象通过 `ref_ptr` 互相引用,会导致内存泄漏(计数永不归零)。 - **解决**:使用 `osg::observer_ptr`(弱引用)打破循环。 ```cpp class A : public osg::Referenced { public: osg::ref_ptr<B> b; }; class B : public osg::Referenced { public: osg::observer_ptr<A> a; // 弱引用,避免循环 }; ``` #### **(2) 避免裸指针操作** - **错误示例**: ```cpp osg::Node* rawNode = new osg::Node; osg::ref_ptr<osg::Node> node1(rawNode); osg::ref_ptr<osg::Node> node2(rawNode); // 危险!rawNode 可能被重复释放 ``` - **正确做法**:始终通过 `ref_ptr` 管理新对象。 #### **(3) 性能优化** - 在频繁创建/销毁对象的场景(如粒子系统),使用 `osg::ref_ptr` 的引用计数可能成为瓶颈。此时可考虑对象池或手动管理。 --- ### **6. 示例代码** #### **(1) 基本生命周期管理** ```cpp #include <osg/ref_ptr> #include <osg/Geode> #include <osg/ShapeDrawable> int main() { // 创建一个 Geode 节点并添加图形 osg::ref_ptr<osg::Geode> geode = new osg::Geode; osg::ref_ptr<osg::ShapeDrawable> shape = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0,0,0), 1.0)); geode->addDrawable(shape.get()); // 传递 ref_ptr 到其他函数 processNode(geode); // 函数返回后,geode 和 shape 的引用计数减 1 // 若无其他引用,对象自动释放 return 0; } ``` #### **(2) 循环引用处理** ```cpp class Parent : public osg::Referenced { public: osg::ref_ptr<Child> child; }; class Child : public osg::Referenced { public: osg::observer_ptr<Parent> parent; // 弱引用 }; int main() { osg::ref_ptr<Parent> p = new Parent; osg::ref_ptr<Child> c = new Child; p->child = c; c->parent = p; // 不会增加引用计数 p = nullptr; // Parent 对象被释放 c = nullptr; // Child 对象被释放 return 0; } ``` --- ### **7. 高级用法** #### **(1) 自定义引用计数行为** 通过继承 `osg::Referenced` 并重写 `unref()` 方法,可以实现自定义的释放逻辑(如延迟删除)。 #### **(2) 与 `osg::Object` 结合** OSG 中的 `osg::Object` 类(如 `osg::Texture`、`osg::StateSet`)已内置引用计数,推荐直接使用 `ref_ptr` 管理: ```cpp osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D; texture->setImage(new osg::Image); ``` --- ### **总结** - **`osg::ref_ptr`** 是 OSG 中管理对象生命周期的核心工具,通过引用计数自动释放内存。 - **关键点**: 1. 专为 OSG 对象设计,与 `osg::Referenced` 配合使用。 2. 避免循环引用(结合 `osg::observer_ptr`)。 3. 线程安全,但需谨慎处理裸指针。 - **适用场景**:所有 OSG 对象(如节点、几何体、纹理、状态集等)。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值