函数返回安全 boost::multi_array_ref 吗?

Is safe boost::multi_array_ref returned by a function?

我正在尝试使用 boost::multi_array_ref 在我的代码中使用连续数据块。但是我担心如果我使用下面的代码,一维C数组将不会被确认保存:

#include <iostream>
#include "boost/multi_array.hpp"
boost::multi_array_ptr<double, 2> test(int N,int c,int d) {
    double *data = new double[N];
    boost::multi_array_ref<double, 2> a(data, boost::extents[c][d]);
    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 10; j++) {
            a[i][j] = 10 * i + j;
        }
    }
    return a;
}
int main()
{
    boost::multi_array_ptr<double, 2> a = test(100000000,10000,10000);
    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 10; j++) {
            std::cout << a[i][j] << std::endl;
        }
    }
}

结果是对的,我想用std::unique_ptr代替C风格数组,但是Visual Studio告诉我:

no instance of constructor "boost::multi_array_ref<T, NumDims>::multi_array_ref [with T=double, NumDims=2Ui64]" matches the argument list   

我不知道boost::multi_array_ref需要哪种参数。为什么 std::unique_ptr 不能用作参数但 C 样式数组可以?我可以放心地使用 C 样式数组吗?函数返回的 boost::multi_array_ref 安全吗?

我确定会导致内存泄漏,但是如何解决呢?

我找到了一个完美的解决方案 without boost

一个self-defined二维数组(矩阵)class

有boost的方案是sehe的答案

double *data = new double[N];

这是一个原始指针,no-one 拥有分配。你是正确的,它会导致内存泄漏。但是,既然要包含所有权,为什么还要用multi_array_ref?

Live On Compiler Explorer

#include <algorithm>
#include <numeric>
#include "boost/multi_array.hpp"

auto test(int c, int d) {
    boost::multi_array<double, 2> a(boost::extents[c][d]);
    std::iota(a.data(), a.data()+a.num_elements(), 0);
    return a;
}

#include <fmt/ranges.h>
int main()
{
    boost::multi_array<double, 2> a = test(4, 5);

    fmt::print("{}\n", a);
    fmt::print("{}\n", test(3, 6));
    fmt::print("{}\n", test(6, 2));
}

打印:

[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]
[[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16, 17]]
[[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11]]

并且没有内存泄漏。

如果您需要 multi-array-ref:

您可能会通过拥有智能指针来解决问题:

using ARef    = boost::multi_array_ref<double, 2>;
using ARefPtr = boost::shared_ptr<ARef>;

现在您可以像以前一样分配数据 - 但没有泄漏:

auto test(int c, int d) {
    auto data = boost::shared_ptr<double[]>(new double[c*d]);

See this post for details and compatibility with std::shared_ptr

并使用别名构造函数在更改时共享数据所有权 ARef 的表观元素类型:

    auto a = ARefPtr(data, new ARef(data.get(), boost::extents[c][d]));
    std::iota(a->data(), a->data() + a->num_elements(), 0);
    return a;
}

#include <fmt/ranges.h>
int main()
{
    ARefPtr a = test(4, 5);

    fmt::print("{}\n", *a);
    fmt::print("{}\n", *test(3, 6));
    fmt::print("{}\n", *test(6, 2));
}

当然,现在你处理的是智能指针,所以你需要更多de-references。看到了吧Live:

[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]
[[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16, 17]]
[[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11]]