C++ 矩阵类重载运算符通过引用返回

标签 c++ matrix return binary-operators

我正在编写模板化矩阵类,当从运算符按值返回时出现堆栈溢出:+,-,* 对于较大的矩阵。我宁愿以某种方式通过引用返回以减轻堆栈并避免额外的复制,但是,我必须返回一个用 构造的对象。新品 并打破“使用 删除 为每个 ”的一般规则。由于复制开销和堆栈限制问题,我无法按值返回,并且由于内存泄漏,我也无法按引用返回,那我该怎么办?

这是我的产品功能(矩阵包含二维数组元素):

    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_typeR::value_type 不是
    相同,这不会编译。这是你想要的,除了
    错误消息将远未明确。)

    结果是你从来没有真正构建过中间体,
    临时矩阵。

    可以想象,上面的解决方案大大简化了。
    你需要额外的代码来处理错误,而我不需要
    认为并行化是微不足道的。但它避免了
    构建所有中间矩阵,即使是复杂的
    表达式。

    (可以使用抽象基类使用相同的技术,
    MatrixAccessor ,使用纯虚拟 setter/getter ,并推导Matrix以及所有的 helper ,如 MatrixMultiply
    它。恕我直言,这更具可读性,并且错误消息
    从编译器肯定会更容易理解。结果将是
    只要编译器实际内联所有成员
    职能。但这是一个很大的如果,因为可以有
    重要的函数嵌套。)
  • 关于C++ 矩阵类重载运算符通过引用返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14082745/

    相关文章:

    c - 通过在 C 中插值行生成大小为 (2n+1)×n 的新矩阵

    matrix - Julia 矩阵切片

    android - 根据矩阵将触摸值转换为点

    actionscript-3 - 从 Switch Case 返回值时出错?

    c# - 递归 C# 函数从 for 循环内部返回 - 如何转换为 F#?

    c - 为什么 main() 不需要返回类型(比如 int),即使它返回一个整数?

    c++ - 潜在的 g++ 模板错误?

    c++ - 使用 OOP 和 STL 在 C++ 中解析缓冲区

    c++ - std::copy 的输出速度比 std::cout 快吗?

    C++ getter 函数 : const and non const