【问题标题】:Return a pointer or value when objects are large当对象很大时返回一个指针或值
【发布时间】:2020-04-27 13:06:12
【问题描述】:

假设我们创建了一个 Matrix<n, m> 类,它将 nxm 个整数存储在成员变量 std::array<std::array<int, m>, n> inner; 中。现在有两种添加方式:

方法一)按值返回(constexpr可以)

template<int n, int m> class Matrix {
    ...
    constexpr Matrix add(const Matrix& that) const {
        matrix ret;
        for (int y = 0; y < n; y++)
            for (int x = 0; x < m; x++)
                ret.inner[y][x] = this->inner[y][x] + that.inner[y][x];
        return ret;
    }
    ...
}

方法2)返回指针(constexpr是不可能的)

template<int n, int m> class Matrix {
    ...
    Matrix *add(const Matrix& that) const {
        Matrix *ret = new Matrix();
        for (int y = 0; y < n; y++)
            for (int x = 0; x < m; x++)
                ret->inner[y][x] = this->inner[y][x] + that.inner[y][x];
        return ret;
    }
    ...
}

我的程序需要对1000x1000 矩阵(图像)进行算术运算,所以使用 方法 1 我会立即得到一个 stackoverflow。我的程序还适用于需要在编译时计算的小型4x4 矩阵(量子计算中的密度矩阵),因此在这些constexpr 初始化中使用方法2 是不可能的。

问题:我是否需要为每个返回 Matrix 的方法制作两个版本? (一个返回Matrix,另一个返回Matrix*)这将是很多重复的代码。这个问题有多普遍?是否有另一种使用堆的方法,以便constexpr 也可以使用 方法 2

This answer 提到移动语义已经将偏好稍微转移到了方法 1。但是由此产生的堆栈溢出呢?

【问题讨论】:

  • 不要使用std::array&lt;std::array&lt;int, m&gt;, n&gt;,使用适当大小的std::vector&lt;int&gt;
  • 不幸的是,这是不可能的。我确实调用了一个外部 dll(数学内核库),它期望矩阵像 std::array 一样存储。
  • 实际导致溢出的部分不在您发布的代码中。如果Matrix 确实管理动态内存,则不需要动态分配Matrix
  • 如果你说的是Intel的MKL,它在C接口中使用一维数组,没有C++接口。
  • 只有 1000x1000?如果您没有太多线程,或者您使用的是 64 位二进制文​​件,则只需增加堆栈大小即可。

标签: c++ matrix constexpr


【解决方案1】:

我的提议:

template<size_t n, size_t m>
class Matrix
{
public:
    Matrix& operator+=(const Matrix& other)
    {
        return *this;
    }
};

template<size_t n, size_t m>
Matrix<n, m> constexpr operator+(Matrix<n, m> x, Matrix<n, m> const& y)
{
    x += y;
    return x;
}

template<size_t n, size_t m>
std::unique_ptr<Matrix<n, m>> add(Matrix<n, m> const* x, Matrix<n, m> const* y)
{
    auto result = std::make_unique<n, m>(*x);
    *result += *y;
    return std::unique_result;
}

现在您可以对小矩阵使用按值加法:

Matrix<10, 12> m1, m2;
auto m3 = m1 + m2;

以及您可以动态分配的大型矩阵:

auto pm1 = std::make_unique<Matrix<12, 10>>();
auto pm2 = std::make_unique<Matrix<12, 10>>();
auto pm3 = add(pm1.get(), pm2.get());

甚至:

auto pm3 = std::make_unique<Matrix<12, 10>>(pm1);
*pm3 += *pm2;

【讨论】:

  • 我想你忘记了operator+= 中的实际添加。也许至少放一个占位符评论。
  • @FrançoisAndrieux 它在课堂上......承认,我没有在里面添加任何东西,但为了演示就足够了。
猜你喜欢
  • 2016-05-01
  • 1970-01-01
  • 2012-10-24
  • 2020-05-15
  • 2014-08-16
  • 2016-07-07
  • 1970-01-01
  • 2013-02-16
  • 1970-01-01
相关资源
最近更新 更多