我正在编写模板化矩阵类,当从运算符按值返回时出现堆栈溢出:+,-,* 对于较大的矩阵。我宁愿以某种方式通过引用返回以减轻堆栈并避免额外的复制,但是,我必须返回一个用 构造的对象。新品 并打破“使用 删除 为每个 新 ”的一般规则。由于复制开销和堆栈限制问题,我无法按值返回,并且由于内存泄漏,我也无法按引用返回,那我该怎么办?
这是我的产品功能(矩阵包含二维数组元素):
template<typename T, unsigned int n, unsigned int m> template<unsigned int m2>
Matrix<T,n,m2> Matrix<T,n,m>::operator*(Matrix<T,m,m2>& M) {
T prod[n][m2];
if(n*m < GPUAccelerationThreshold)
for(int i = 0; i < n; i++)
for(int j = 0; j < m2; j++) {
prod[i][j] = elems[i][0] * M(0, j);
for(int p = 1; p < m; p++)
prod[i][j] += elems[i][p] * M(p, j);
}
else {
array_view<T, 2> product(n, m2, *prod);
array_view<T, 2> a(n, m, *elems);
array_view<T, 2> b(m, m2, M.elems[0]);
parallel_for_each(
product.extent,
[=](index<2> idx) restrict(amp) {
int row = idx[0];
int col = idx[1];
for (int inner = 0; inner < m; inner++) {
product[idx] += a(row, inner) * b(inner, col);
}
}
);
product.synchronize();
}
return Matrix<T,n,m2>(prod);
}
我写这个类是因为我想在 GPU 上提升一些矩阵运算(使用 MS 放大器)。我搜索了一个现有的解决方案,找到了 GPU 加速的线性代数库,但我在它们中找不到的是一个带有 +、-、* 运算符的简单矩阵类。也许有人可以推荐我?
最佳答案
三个快速评论:
Matrix
类使用了动态分配。你不显示你的
Matrix
类,但如果你数据是:
T myData[n][m];
您可能想将其更改为:
std::vector myData;
,将其初始化为大小
n * m
在构造函数中,和operator[]
中的单指数计算(这应该如果要进行任何边界检查,请返回代理)。
或者,您可以使用
operator()( int i, int j )
为了访问一个元素:是否
myMatrix( i, j )
或者myMatrix[i][j]
优先访问取决于您询问的对象。尽管此解决方案略微增加了总内存使用量(但
非常轻微),它将堆栈占用空间减少到几个
十几个字节,不管矩阵的大小。
同样传统上,矩阵类没有维度
他们的模板参数的一部分。这是否是一件好事
与否是有争议的。你会得到更好的类型检查(和
编译时的错误,而不是运行时)与您的解决方案,
但是如果维度是构造函数的参数,那么
与模板参数相比,您可以从命令行读取它们
或配置文件或其他什么。这是经典的安全
与灵活性权衡。
关于您的问题,没有尺寸
模板参数意味着所有
T
类型的矩阵有同类型。因此,您可以访问矩阵的内部
从您的成员函数返回,您不再需要
中级
T prod[n][m2]
.当然,你可以把所有Matrix
的实例化 friend ,或者只是使用访问函数来设置值。无论如何,你不想要一个
中级
T prod[n][m2]
;这不仅需要很多堆栈内存,这意味着您必须复制结果。
最后,这有点高级:在最佳矩阵中
类,
operator*
不返回矩阵,而是一个助手类,大致如下:
模板
类矩阵乘法
{
L const* myLhs;
R const* myRhs;
民众:
typedef T value_type;
矩阵乘法( L const& lhs, R const& rhs )
: myLhs( &lhs )
, myRhs( &rhs )
{
}
int getX() 常量
{
返回 myLhs->getX();
}
int getY() 常量
{
返回 myRhs->getY();
}
T get( int i, int j ) const
{
返回计算IJ(myLhs,myRhs);
}
};
然后提供模板化的构造函数和赋值运算符
使用
getX()
, getY()
和 get( i, j )
.您的operator*
也是一个模板,它返回一个MatrixMultiply
:模板
矩阵乘法
运算符*( L const& lhs, R const& rhs )
{
返回矩阵乘法(lhs,rhs);
}
(请注意,如果
L::value_type
和 R::value_type
不是相同,这不会编译。这是你想要的,除了
错误消息将远未明确。)
结果是你从来没有真正构建过中间体,
临时矩阵。
可以想象,上面的解决方案大大简化了。
你需要额外的代码来处理错误,而我不需要
认为并行化是微不足道的。但它避免了
构建所有中间矩阵,即使是复杂的
表达式。
(可以使用抽象基类使用相同的技术,
说
MatrixAccessor
,使用纯虚拟 setter/getter ,并推导Matrix
以及所有的 helper ,如 MatrixMultiply
从它。恕我直言,这更具可读性,并且错误消息
从编译器肯定会更容易理解。结果将是
只要编译器实际内联所有成员
职能。但这是一个很大的如果,因为可以有
重要的函数嵌套。)
关于C++ 矩阵类重载运算符通过引用返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14082745/