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

时间:2014-01-16 12:08:59

标签: c++ casting eigen expression-templates temporaries

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

这是一个引起麻烦的简短例子。持有者只持有一个特征矩阵,夏天需要两个持有者,并在你调用get()时输出他们持有的两个矩阵的总和。当sum表达式模板被计算到矩阵中时,后面的测试失败(segfault或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,它可以正常工作。
  • 我怀疑这个问题是由悬挂参考引起的,但无法证明。

1 个答案:

答案 0 :(得分:1)

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