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

使用Eigen::Ref初始化const引用成员变量时的野值问题排查

Eigen引用成员变量访问出现垃圾值的原因分析

问题场景

我定义了UnscentedUpdateStrategy模板类,尝试通过构造函数传入的Eigen::Ref类型参数,初始化两个const引用成员变量。构造函数内的打印显示current_predicted_sigma_points_初始化正确,但调用Update函数时,该成员变量出现垃圾值,而weights_仍正常。将成员变量改为Eigen::Ref类型后问题消失,想了解原场景下的问题原因。

对应代码如下:

template <typename ProcessModel, typename MeasurementModel>
class UnscentedUpdateStrategy
{
  public:
    UnscentedUpdateStrategy(
        const Eigen::Ref<const ukf_utils::PredictedSigmaMatrix<ProcessModel, ProcessModel::n_sigma_points>>
            current_predicted_sigma_points,
        const Eigen::Ref<const Eigen::Vector<double, ProcessModel::n_sigma_points>> weights)
        : current_predicted_sigma_points_{current_predicted_sigma_points}, weights_{weights}
    {
        std::cout << "Matrix Param: " << current_predicted_sigma_points << std::endl;
        std::cout << "Matrix Member: " << current_predicted_sigma_points_ << std::endl;
    }

    void Update(const Eigen::Ref<const typename MeasurementModel::PredictedVector>& measure,
                const simpleukf::ukf_utils::MeanAndCovariance<ProcessModel>& current_hypotesis,
                simpleukf::ukf_utils::MeanAndCovariance<ProcessModel>& mean_and_cov_out) const
    {
        simpleukf::ukf_utils::PredictedSigmaMatrix<MeasurementModel, ProcessModel::n_sigma_points>
            measurement_predicted_sigma_matrix_out;

        std::cout << "Matrix Member Update: " << current_predicted_sigma_points_ << std::endl;
        std::cout << "Weights Update: " << weights_ << std::endl;

        auto measurement_prediction = ukf_utils::PredictMeanAndCovarianceFromSigmaPoints<MeasurementModel>(
            measurement_predicted_sigma_matrix_out, current_predicted_sigma_points_, weights_);
        // std::forward<const MeasurementPredictionArgs>(args)...);

        // add measurement noise covariance matrix
        measurement_prediction.covariance += MeasurementModel::noise_matrix_squared;
        
        // create matrix for cross correlation: predicted measurement `measurement_prediction.mean` and pred covariance
        // `measurement_prediction.covariance`
        const auto cross_correlation_matrix =
            ukf_utils::ComputeCrossCorrelation<ProcessModel, MeasurementModel, ProcessModel::n_sigma_points>(
                current_predicted_sigma_points_,
                current_hypotesis.mean,
                measurement_predicted_sigma_matrix_out,
                measurement_prediction.mean,
                weights_);

        // Kalman gain K;
        Eigen::Matrix<double, ProcessModel::n, MeasurementModel::n> K =
            cross_correlation_matrix * measurement_prediction.covariance.inverse();

        // residual
        typename MeasurementModel::PredictedVector measure_diff = measure - measurement_prediction.mean;

        // angle normalization
        models_utils::AdjustIfNeeded<MeasurementModel>(measure_diff);

        // update state mean and covariance matrix
        mean_and_cov_out.mean = current_hypotesis.mean + K * measure_diff;
        mean_and_cov_out.covariance =
            current_hypotesis.covariance - K * measurement_prediction.covariance * K.transpose();
    }

  private:
    // TODO: should we keep a copy or not?
    const ukf_utils::PredictedSigmaMatrix<ProcessModel, ProcessModel::n_sigma_points>& current_predicted_sigma_points_;
    const Eigen::Vector<double, ProcessModel::n_sigma_points>& weights_;
};

原因分析

核心问题:悬垂引用

问题根源是构造函数参数绑定的临时对象生命周期到期,导致成员引用变成悬垂引用:

  • 当向构造函数传入的不是ukf_utils::PredictedSigmaMatrix类型的直接对象,而是Eigen表达式(如矩阵运算结果、转置、切片)或需要隐式转换的对象时,Eigen::Ref<const PredictedSigmaMatrix>会触发Eigen创建一个临时的PredictedSigmaMatrix对象存储数据,再绑定到这个临时对象。
  • 根据C++规则,函数参数中的临时对象生命周期仅维持到函数调用结束。构造函数执行完毕后,该临时对象会被销毁,而成员变量current_predicted_sigma_points_是绑定到该临时对象的const引用,此时就变成了悬垂引用。
  • 构造函数内打印正常是因为临时对象尚未销毁,但调用Update时,临时对象早已被释放,访问该引用就会读取到内存中的垃圾值。
  • weights_未出现问题,大概率是因为传入的weights是一个生命周期长于UnscentedUpdateStrategy对象的持久化变量(如全局变量、栈上长期存在的变量、堆上对象),成员引用绑定的是有效内存,不会出现悬垂。

改为Eigen::Ref成员后问题消失的原因

Eigen::Ref是智能包装类而非普通引用:

  • 它内部会存储指向数据的指针、矩阵维度等元信息,用构造函数的Eigen::Ref参数初始化Eigen::Ref成员时,会正确传递对原数据的引用关系。
  • 若原数据是临时对象仍有悬垂风险,但实际场景中,可能修改后传入的current_predicted_sigma_points绑定的是持久化对象的Eigen::Ref,或Eigen::Ref的内部机制避免了临时对象的绑定(比如要求直接绑定到持久化对象,否则编译报错)。

稳妥解决方案

最可靠的方式是存储对象副本而非引用,除非能100%保证传入的原对象生命周期始终长于UnscentedUpdateStrategy对象:

private:
    const ukf_utils::PredictedSigmaMatrix<ProcessModel, ProcessModel::n_sigma_points> current_predicted_sigma_points_;
    const Eigen::Vector<double, ProcessModel::n_sigma_points> weights_;

若必须使用引用,需确保构造时传入的是生命周期足够长的持久化对象,且避免传入Eigen表达式或临时对象。

内容的提问来源于stack exchange,提问作者Andrea Nisticò

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 16:52:14