我想使用表达式模板来创建一个跨语句持续存在的对象树。构建树最初涉及使用 Eigen 线性代数库进行一些计算。持久表达式模板将具有其他方法来通过以不同方式遍历树来计算其他数量(但我还没有)。
为了避免临时对象超出范围的问题,子表达式对象通过std::unique_ptr
. 随着表达式树的构建,指针应该向上传播,这样持有根对象的指针就可以确保所有对象都保持活动状态。由于 Eigen 创建的表达式模板包含对在语句末尾超出范围的临时对象的引用,因此情况变得复杂,因此必须在构建树时评估所有 Eigen 表达式。
val
下面是一个按比例缩小的实现,当类型是一个持有整数的对象时,它似乎可以工作,但是对于 Matrix 类型,它在构造output_xpr
对象时会崩溃。崩溃的原因似乎是 Eigen 的矩阵乘积表达式模板 ( Eigen::GeneralProduct
) 在使用之前就已损坏。但是,在崩溃发生之前,我自己的表达式对象或 of 的析构函数GeneralProduct
似乎都没有被调用,并且 valgrind 没有检测到任何无效的内存访问。
任何帮助都感激不尽!我也很欣赏关于我将移动构造函数与静态继承一起使用的评论,也许问题出在某个地方。
#include <iostream>
#include <memory>
#include <Eigen/Core>
typedef Eigen::MatrixXi val;
// expression_ptr and derived_ptr: contain unique pointers
// to the actual expression objects
template<class Derived>
struct expression_ptr {
Derived &&transfer_cast() && {
return std::move(static_cast<Derived &&>(*this));
}
};
template<class A>
struct derived_ptr : public expression_ptr<derived_ptr<A>> {
derived_ptr(std::unique_ptr<A> &&p) : ptr_(std::move(p)) {}
derived_ptr(derived_ptr<A> &&o) : ptr_(std::move(o.ptr_)) {}
auto operator()() const {
return (*ptr_)();
}
private:
std::unique_ptr<A> ptr_;
};
// value_xpr, product_xpr and output_xpr: expression templates
// doing the actual work
template<class A>
struct value_xpr {
value_xpr(const A &v) : value_(v) {}
const A &operator()() const {
return value_;
}
private:
const A &value_;
};
template<class A,class B>
struct product_xpr {
product_xpr(expression_ptr<derived_ptr<A>> &&a, expression_ptr<derived_ptr<B>> &&b) :
a_(std::move(a).transfer_cast()), b_(std::move(b).transfer_cast()) {
}
auto operator()() const {
return a_() * b_();
}
private:
derived_ptr<A> a_;
derived_ptr<B> b_;
};
// Top-level expression with a matrix to hold the completely
// evaluated output of the Eigen calculations
template<class A>
struct output_xpr {
output_xpr(expression_ptr<derived_ptr<A>> &&a) :
a_(std::move(a).transfer_cast()), result_(a_()) {}
const val &operator()() const {
return result_;
}
private:
derived_ptr<A> a_;
val result_;
};
// helper functions to create the expressions
template<class A>
derived_ptr<value_xpr<A>> input(const A &a) {
return derived_ptr<value_xpr<A>>(std::make_unique<value_xpr<A>>(a));
}
template<class A,class B>
derived_ptr<product_xpr<A,B>> operator*(expression_ptr<derived_ptr<A>> &&a, expression_ptr<derived_ptr<B>> &&b) {
return derived_ptr<product_xpr<A,B>>(std::make_unique<product_xpr<A,B>>(std::move(a).transfer_cast(), std::move(b).transfer_cast()));
}
template<class A>
derived_ptr<output_xpr<A>> eval(expression_ptr<derived_ptr<A>> &&a) {
return derived_ptr<output_xpr<A>>(std::make_unique<output_xpr<A>>(std::move(a).transfer_cast()));
}
int main() {
Eigen::MatrixXi mat(2, 2);
mat << 1, 1, 0, 1;
val one(mat), two(mat);
auto xpr = eval(input(one) * input(two));
std::cout << xpr() << std::endl;
return 0;
}