当对象很大时返回一个指针或值

Posted

技术标签:

【中文标题】当对象很大时返回一个指针或值【英文标题】: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 我会立即得到一个 ***。我的程序还适用于需要在编译时计算的小型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 位二进制文​​件,则只需增加堆栈大小即可。 【参考方案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 它在课堂上......承认,我没有在里面添加任何东西,但为了演示就足够了。

以上是关于当对象很大时返回一个指针或值的主要内容,如果未能解决你的问题,请参考以下文章

函数可以返回一个局部对象,而不能返回一个局部对象的引用(指针):

当键或值很大时,为什么redis hash会从ziplist转换为hashtable?

当函数返回时,指向超出范围的对象的 C++ 指针 - 为啥会这样?

C ++何时返回指针[关闭]

返回基类对象中的派生对象指针

在块中返回非指针对象时出现问题