使用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ò
相关产品推荐
相关产品推荐

