【问题标题】:Take ownership of referenced Eigen3 matrix获取引用的 Eigen3 矩阵的所有权
【发布时间】:2018-01-28 02:46:26
【问题描述】:

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

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

来自 pybind11 的示例在此处使用 Eigen::Ref (pybind11 doc) 提到了 C++ 和 Python 之间的 pass-by-reference。

我尝试修改一个示例(来自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

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

      • 感谢您解释为什么 std::move 不起作用。
      【解决方案3】:

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

      【讨论】:

      • 在 pybind11 端不起作用。 pybind11 复制std::vector 中的数组。使用Eigen::Ref 可以避免复制,但这不会让我使用std::move
      • 使用 std::vector<:ref> 不会让我分配一个新数组并将其附加到函数内的向量中。
      猜你喜欢
      • 2015-10-28
      • 2015-03-24
      • 2012-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多