取得参考Eigen3矩阵的所有权

时间:2018-01-28 02:46:26

标签: python c++ move-semantics eigen3 pybind11

如何通过引用将特征矩阵A传递给函数,然后窃取A?

的所有权

我正在为Python编写一个C ++扩展,它接收两个std::vector<Eigen::Ref<Mat> >并返回std::vector<Mat>。返回矢量的每个元素可以是输入矢量中引用的新矩阵或旧矩阵。

pybind11的例子提到了C ++和Python之间的引用,Eigen::Ref在这里(pybind11 doc)。

我尝试修改一个例子(来自old bug report)。但是源不会移动到目标。这是因为源矩阵最后不是空的。

测试:

#include <iostream>
#include <eigen3/Eigen/Dense>

typedef Eigen::MatrixXd Mat;

Mat func(Eigen::Ref<Mat> ref) {
    Mat target(std::move(ref));
    return target;
}

int main() {
  const std::size_t n = 2;
  Mat source = Mat::Zero(n, n);
  Mat target = func(source);
  std::cout << "source\n" << source << "\n";
  std::cout << "target\n" << target << "\n";
  return 0;
}

结果:

source
0 0
0 0
target
0 0
0 0

3 个答案:

答案 0 :(得分:2)

这是不可能的,因为Ref<MatrixXd>的内存布局比MatrixXd更通用,它甚至不拥有它引用的数据!因此,唯一的解决方案是传递MatrixXd&

答案 1 :(得分:1)

函数内的

ref是一个局部变量。你可以移动它,没关系。但是你无法窃取所有权,因为它通过价值传递,你无法访问调用者工作区中存在的对象。此外,您正在将引用移动到Mat的构造函数,它将简单地通过复制创建一个新矩阵(我认为,因为您无法将一种类型的对象移动到另一种类型的对象)。

您看到的情况是因为ref在来电者的工作区中与source共享数据。这是两个指向相同数据的不同对象。

如果你要返回引用对象(而不是像你那样创建一个用引用对象初始化的新矩阵),那么引用可能比引用的原始对象更长,并且会引起麻烦。

答案 2 :(得分:0)

这适用于C ++:

测试:

#include <iostream>
#include <eigen3/Eigen/Dense>
#include <vector>

typedef Eigen::MatrixXd Mat;

void print_mats(std::string const& s, const std::vector<Mat>& v) {
    std::cout << s << "\n";
    for (int i = 0; i < v.size(); ++i) {
        std::cout << "matrix #" << i << "\n";
        std::cout << v[i] << "\n";
    }
}

std::vector<Mat> func(std::vector<Mat>& source) {
    std::vector<Mat> target;
    target.emplace_back(std::move(source[0]));
    return target;
}

int main() {
    const std::size_t n = 2;
    std::vector<Mat> source;
    // can't move Mat::Zero(n, n), which is a const expression.
    // no need for source.emplace_back(std::move(Mat::Zero(n, n)));
    source.emplace_back(Mat::Zero(n, n));
    print_mats("source before", source);
    std::vector<Mat> target = func(source);
    print_mats("source after", source);
    print_mats("target", target);

    return 0;
}

结果:

source before
matrix #0
0 0
0 0
source after
matrix #0

target
matrix #0
0 0
0 0