2014-01-16 12 views
0

Я пишу библиотеку, которая хранит шаблоны выражений Eigen в качестве переменных-членов для выполнения сложных вычислений, которые необходимо выполнить. Однако кажется, что я не могу хранить или возвращать эти шаблоны выражений, если они не преобразуются напрямую в MatrixXd или аналогично. Это заставляет каждый шаг быть временно сохраненным и разрушает эффективность всей конструкции.cast from Eigen :: CwiseBinaryOp to MatrixXd вызывает segfault

Вот краткий пример, который вызывает проблемы. Держатель просто удерживает матрицу Eigen, а Summer берет два держателя и выводит сумму двух матриц, которые они удерживают, когда вы вызываете get(). Последующий тест не выполняется (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; 
} 
  • В заголовочном файле, если вы используете закомментирована ЬурейеЕ вместо этого, он отлично работает.
  • Я подозреваю, что проблема связана с оборванной ссылкой, но не может ее доказать.
+0

Я не вижу ничего явно неправильного с вашим кодом. Как Summer :: result_type отличается от Eigen :: MatrixXd? –

+0

Лето :: result_type не Eigen :: MatrixXd, см. Typedef! – yannick

+0

Таким образом, вопрос, _how_ они отличаются друг от друга. –

ответ

1

Это потому, что Holder::get возвращает копию матрицы как временную. Затем это временное значение сохраняется в качестве ссылки на const объектом CWiseBinaryOp, возвращаемым Summer::get, тогда это временное удаление и, наконец, когда оценивается expr, expr ссылается на удаленные объекты. Вы можете исправить эту проблему, сделав Holder::get, возвращая константу ссылки на матрицу.

+0

см. Также http://forum.kde.org/viewtopic.php?f=74&t=119244&p=300334#p300334 – yannick