问题描述
我正在写一个库,存储Eigen表达式模板作为成员变量,以进行需要做的复杂计算。但是,似乎我不能存储或返回这些表达式模板,除非它们直接在MatrixXd或类似的转换。这迫使每一步都被保存到一个临时的,并且浪费整个设计的效率。
这里有一个简短的例子,导致麻烦。 Holder只是拥有一个Eigen矩阵,而Summer需要两个持有者并输出他们持有的两个矩阵的总和,当你调用get()。
包含文件
b $ b
#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,HoldRight class>
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>矩阵
typedef Summer< MatrixHolder,MatrixHolder> MatrixSummer;
#endif / * PB_SIMPLE_H * /
简单测试
#includePbSimple.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); //将求和结果强制转换为新的矩阵,在这里失败
return 0;
}
- 在包含文件中,如果使用
我怀疑这个问题是由于一个悬挂的引用,但不能证明它。
这是因为 Holder :: get
返回一个矩阵的副本。然后,这个临时变量作为const引用存储为由 Summer :: get
返回的 CWiseBinaryOp
对象,删除,最后当 expr
得到求值时, expr
正在引用删除的对象。你可以通过 Holder :: get
返回矩阵的const引用来修复这个问题。
I am writing a library that stores Eigen expression templates as member variables to do the complicated calculations it needs to do. However, it seems like I'm not able to store or return these expression templates unless they are directly converted in MatrixXd or alike. This forces every step to be saved to a temporary, and ruins the efficiency of the whole design.
Here's a short example that causes the trouble. Holder just holds an Eigen matrix, and Summer takes two holders and outputs the sum of the two matrices they hold when you call get(). The test that follows fails (segfault or std::bad_alloc) when the sum expression template is evaluated into a matrix.
Include file
#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 */
simple test
#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;
}
- In the include file, if you use the commented out typedef instead, it works fine.
- I suspect the problem is due to a dangling reference, but can't prove it.
This is because Holder::get
returns a copy of the matrix as a temporary. Then this temporary is stored as a const reference by the CWiseBinaryOp
object returned by Summer::get
, then this temporary is deleted, and finally when expr
gets evaluated, expr
is referencing deleted objects. You can fix this issue by making Holder::get
returns a const reference to the matrix.
这篇关于从Eigen :: CwiseBinaryOp转换到MatrixXd导致segfault的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!