获取引用的 Eigen3 矩阵的所有权

Take ownership of referenced Eigen3 matrix

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

我正在为 Python 编写一个 C++ 扩展,它包含两个 std::vector<Eigen::Ref<Mat> > 和 returns 一个 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

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

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

如果您要 return 引用对象(而不是像您那样创建一个用引用对象初始化的新矩阵),那么引用可能会比引用的原始对象长寿,并造成麻烦。

这是不可能的,因为 Ref<MatrixXd> 的内存布局比 MatrixXd 更通用,它甚至不拥有它引用的数据!所以你唯一的解决办法是通过 MatrixXd&.

这适用于 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