簡體   English   中英

使用vector / initilizer列表的任何類型的C ++ 11動態多維數組

[英]C++11 dynamic multidimensional array of any type using vector/initilizer list

如何創建一個多維數組(矩陣),其維度在運行時確定。

最好的方法似乎是采用建築尺寸向量,並采用偏移矢量來訪問單個元素

這也將允許使用初始化列表:

這應該采用在編譯時確定的類型矩陣,因此模板是有意義的

應該適當使用C ++ 11特性,為lambda提供獎勵積分

用法示例:

int main(int, char **)
{
        static const std::size_t d1{2};
        static const std::size_t d2{3};
        static const std::size_t d3{4};
        multi_vec<std::size_t> q({d1,d2,d3});

        for (std::size_t i1=0; i1 < d1; ++i1)
                for (std::size_t i2=0; i2 < d2; ++i2)
                        for (std::size_t i3=0; i3 < d3; ++i3)
                                q[{i1,i2,i3}]=foo(i1,i2,i3);

        for (std::size_t i1=0; i1 < d1; ++i1)
                for (std::size_t i2=0; i2 < d2; ++i2)
                        for (std::size_t i3=0; i3 < d3; ++i3)
                                std::cout << "{"
                                        << i1 << ","
                                        << i2 << ","
                                        << i3 << "}=> "
                                        << foo(i1,i2,i3) << "=="
                                        << q[{i1,i2,i3}]
                                        << ((foo(i1,i2,i3) == q[{i1,i2,i3}])
                                              ? " good" : " ERROR")
                                << std::endl;
};

這實際上是使用lambdas和std::for_each以及unique_ptr進行內存管理的好地方:

template <class T>
class multi_vec
{
public:
    using param=std::vector<size_t>;

    explicit multi_vec(const param& dimensions)
        : dim{dimensions}, prod {1}
    {
        std::for_each(dim.begin(), dim.end(), [this] (std::size_t val)
        {
            mult.emplace_back(prod);
            prod *= val;
        } );
        ptr.reset(new T[prod]);
    }
    std::size_t capacity() const { return prod; }

    // undefined if elements in lookup != elemenets in dim
    // undefined if any element in lookup
        // is greater than or equal to corresponding dim element
    T& operator[](const param& lookup)
    {
        return ptr[get_offset(lookup)];
    }
    const T operator[](const param& lookup) const
    {
        return ptr[get_offset(lookup)];
    }
private:
    std::size_t get_offset(const param& lookup) const
    {
        std::size_t offset=0;
        auto mit=mult.begin();
        std::for_each(lookup.begin(), lookup.end(), [&offset, &mit] (std::size_t val)
        {
            offset+=*mit * val;
           ++mit;
        } );
        return offset;
    }
    param dim;
    param mult;
    std::size_t prod;
    std::unique_ptr<T[]> ptr;
};

這使用單維數組進行實際存儲並緩存乘法器以便重用因為正常的多維數組例如x[2][3][4]沒有限制檢查,超出范圍被視為未定義而不是不斷檢查可能的值有效。 同樣地,不檢查diminsionality的查找,如果需要,可以添加靜態成員來檢查參數是否有效,就邊界或維度而言。

在這里回答https://stackoverflow.com/a/19725907/2684539

#include <cstddef>

#include <vector>

template<typename T>
class MultiArray
{
public:
    explicit MultiArray(const std::vector<size_t>& dimensions) :
        dimensions(dimensions),
        values(computeTotalSize(dimensions))
    {
        assert(!dimensions.empty());
        assert(!values.empty());
    }

    const T& get(const std::vector<size_t>& indexes) const
    {
        return values[computeIndex(indexes)];
    }
    T& get(const std::vector<size_t>& indexes)
    {
        return values[computeIndex(indexes)];
    }

    size_t computeIndex(const std::vector<size_t>& indexes) const
    {
        assert(indexes.size() == dimensions.size());

        size_t index = 0;
        size_t mul = 1;

        for (size_t i = 0; i != dimensions.size(); ++i) {
            assert(indexes[i] < dimensions[i]);
            index += indexes[i] * mul;
            mul *= dimensions[i];
        }
        assert(index < values.size());
        return index;
    }

    std::vector<size_t> computeIndexes(size_t index) const
    {
        assert(index < values.size());

        std::vector<size_t> res(dimensions.size());

        size_t mul = values.size();
        for (size_t i = dimensions.size(); i != 0; --i) {
            mul /= dimensions[i - 1];
            res[i - 1] = index / mul;
            assert(res[i - 1] < dimensions[i - 1]);
            index -= res[i - 1] * mul;
        }
        return res;
    }

private:
    size_t computeTotalSize(const std::vector<size_t>& dimensions) const
    {
        size_t totalSize = 1;

        for (auto i : dimensions) {
            totalSize *= i;
        }
        return totalSize;
    }

private:
    std::vector<size_t> dimensions;
    std::vector<T> values;
};

int main()
{
    MultiArray<int> m({3, 2, 4});

    m.get({0, 0, 3}) = 42;
    m.get({2, 1, 3}) = 42;

    for (size_t i = 0; i != 24; ++i) {
        assert(m.computeIndex(m.computeIndexes(i)) == i);
    }
    return 0;
}

你使用C. Honestly,C的動態數組優於C ++提供的任何東西。 這是3D數組的代碼:

//Allocation, the type needs some effort to understand,
//but once you do understand it, this is easy:
int width = 7, height = 8, depth = 9;
int (*array)[height][width] = malloc(depth*sizeof(*array));

//Filling, completely natural...
for(int z = 0; z < depth; z++) {
    for(int y = 0; y < height; y++) {
        for(int x = 0; x < width; x++) {
            array[z][y][x] = 42;
        }
    }
}

//Deallocation, trivial...
free(array);

3D數組不過是2D陣列的1D陣列(依次是1D陣列的1D陣列),因此您將指針*array聲明為整數的2D數組int (...)[heigh][width] ,並為depth分配空間這樣的元素malloc(depth*sizeof(*array)) 這完全類似於使用int *array = malloc(length*sizeof(*array));創建一維數組int *array = malloc(length*sizeof(*array)); 其余的是數組指針衰變魔法。

這適用於C,因為C允許數組類型包含動態大小(自C99起)。 這就像在聲明點定義兩個具有聲明大小的常量一樣。 另一方面,C ++仍然堅持數組大小是編譯時常量,因此無法允許動態大小的多維數組。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM