获取引用的 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
如何通过引用将特征矩阵 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