You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用shared_ptr/unique_ptr传递给RTI DDS的StatusCondition构造函数时崩溃

为什么RTI DDS中用shared_ptr替代裸指针会导致StatusCondition崩溃?

你遇到的核心问题是RTI DDS的实体所有权模型和C++智能指针的语义不匹配,尤其是StatusCondition与关联Entity(比如DataReader)的生命周期绑定规则,以及RTI内部的实体管理机制和外部智能指针的冲突。

先拆解你的代码场景

裸指针版本为什么正常?

你的裸指针代码能运行,本质是你手动控制了DataReader的生命周期,确保它在StatusCondition存在期间始终有效。不过这里其实藏了一个潜在的未定义行为:你用临时的dds::sub::Subscriber(participant)构造DataReader,临时Subscriber会在DataReader构造完成后立即销毁——按照RTI DDS的规则,父实体销毁时会自动销毁所有子实体,只是你的测试代码没触发崩溃而已。

为什么shared_ptr会崩溃?

问题出在两个关键规则的冲突:

  1. StatusCondition的本质是引用而非独立对象:根据你给出的API文档,StatusCondition的构造函数不会创建新对象,而是获取目标Entity(比如DataReader)已有的唯一StatusCondition引用。这个引用的生命周期完全绑定到原Entity——Entity销毁时,它的StatusCondition也会被销毁。
  2. RTI DDS实体已有内部生命周期管理:DomainParticipant、Subscriber、DataReader这些实体本身是父子层级结构,父实体销毁时会自动销毁所有子实体;同时内部也有引用计数机制。而std::shared_ptr会额外套一层外部引用计数,这会导致双重计数冲突:
    • 当shared_ptr的引用计数归零时,会直接delete掉DataReader,但RTI内部可能还认为这个实体是有效的,或者StatusCondition还持有它的引用。
    • 这种情况下,StatusCondition访问已被销毁的DataReader内部资源,就会触发底层异常或崩溃。

unique_ptr为什么报错?

如果只是简单替换成unique_ptr,语法上是可行的,报错大概率是因为你在代码中不小心让unique_ptr提前释放了DataReader(比如reset()或者unique_ptr被提前销毁),导致StatusCondition引用悬空。

正确的解决方案:遵循RTI RAII规则结合智能指针

RTI DDS的C++ API本身是基于RAII设计的,不需要手动用new创建实体,也不推荐用shared_ptr管理实体。如果要把StatusCondition作为类成员,核心是确保Entity的生命周期覆盖StatusCondition。

修正后的类成员示例

#include <dds/dds.hpp>
#include <memory>

class MyDDSReader {
private:
    // 按父子层级顺序声明:父实体在前,子实体在后
    dds::domain::DomainParticipant participant_;
    dds::topic::Topic<MyTopic> topic_;
    dds::sub::Subscriber subscriber_;
    // 用unique_ptr动态管理DataReader(如果需要)
    std::unique_ptr<dds::sub::DataReader<MyTopic>> reader_;
    // StatusCondition依赖DataReader,所以声明在reader_之后
    dds::core::cond::StatusCondition status_condition_;

public:
    MyDDSReader()
        : participant_(0),
          topic_(participant_, "example"),
          subscriber_(participant_),
          reader_(new dds::sub::DataReader<MyTopic>(subscriber_, topic_)),
          status_condition_(*reader_) // 此时reader_已完全初始化,实体有效
    {}

    // 析构时按逆序销毁:status_condition_ → reader_ → subscriber_ → topic_ → participant_
    // 确保StatusCondition永远不会访问已销毁的DataReader
};

int main() {
    MyDDSReader reader;
    return 0;
}

关键要点

  1. 实体声明顺序要符合父子层级:父实体先初始化,子实体后初始化;析构时逆序销毁,保证子实体不会在父实体之前被销毁。
  2. 用unique_ptr而非shared_ptr:unique_ptr的所有权语义更简单,不会干扰RTI内部的生命周期管理,只要确保unique_ptr的生命周期覆盖StatusCondition即可。
  3. 避免临时实体:不要用临时的Subscriber/Publisher构造子实体,否则会触发RTI的自动销毁机制,导致子实体被提前回收。

内容的提问来源于stack exchange,提问作者code_fodder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:55:31