从 Eigen::CwiseBinaryOp 转换为 MatrixXd 会导致段错误



我正在编写一个库,将特征表达式模板存储为成员变量,以执行它需要做的复杂计算。但是,我似乎无法存储或返回这些表达式模板,除非它们直接在 MatrixXd 或类似版本中转换。这迫使每个步骤都暂时保存下来,并破坏了整个设计的效率。

下面是一个导致麻烦的简短示例。Holder 只保存一个特征矩阵,而 Summer 取两个 Holder,并在调用 get() 时输出它们持有的两个矩阵的总和。当将总和表达式模板计算到矩阵中时,下面的测试失败(段错误或 std::bad_alloc)。

包含文件

#ifndef PB_SIMPLE_H
#define PB_SIMPLE_H
#include <Eigen/Dense>
template <class EigenType>
class Holder {
   public:
    typedef EigenType result_type;
   private:
    result_type in_;
   public:
    Holder(const EigenType& in) : in_(in) {}
    result_type get() const { return in_; }
};
template <class HoldLeft, class HoldRight>
class Summer {
   public:
    typedef const typename Eigen::CwiseBinaryOp<
        Eigen::internal::scalar_sum_op<double>,
        const typename HoldLeft::result_type,
        const typename HoldRight::result_type> result_type;
    // typedef Eigen::MatrixXd result_type;
   private:
    HoldLeft left_;
    HoldRight right_;
   public:
    Summer(const HoldLeft& left, const HoldRight& right)
        : left_(left), right_(right) {}
    result_type get() const { return left_.get() + right_.get(); }
};
typedef Holder<Eigen::MatrixXd> MatrixHolder;
typedef Summer<MatrixHolder, MatrixHolder> MatrixSummer;
#endif /* PB_SIMPLE_H */

简单测试

#include "PbSimple.h"
#include <Eigen/Dense>
int main(int, char * []) {
  const unsigned int szx=10,szy=3;
  Eigen::MatrixXd x(Eigen::MatrixXd::Constant(szx,szy,1));
  MatrixHolder vx(x);
  Eigen::MatrixXd y(Eigen::MatrixXd::Constant(szx,szy,2));
  MatrixHolder vy(y);
  MatrixSummer vsum(vx,vy);
  auto expr = vsum.get();
  MatrixHolder vz(expr); //force evaluation of sum into new matrix, fails here
  return 0;
}
  • 在包含文件中,如果您改用注释掉的 typedef,它可以正常工作。
  • 我怀疑问题是由于悬而未决的参考,但无法证明这一点。

这是因为Holder::get返回矩阵的副本作为临时矩阵。然后,这个临时被Summer::get返回的CWiseBinaryOp对象存储为const引用,然后删除这个临时,最后当expr被评估时,expr引用已删除的对象。您可以通过使Holder::get返回对矩阵的 const 引用来解决此问题。

最新更新