我正在编写一个库,将特征表达式模板存储为成员变量,以执行它需要做的复杂计算。但是,我似乎无法存储或返回这些表达式模板,除非它们直接在 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 引用来解决此问题。