半动态多维存储对象

Half-dynamic multidimensional storage object

本文关键字:存储 对象 动态      更新时间:2023-10-16

我正在寻找一个c++多维存储对象,该对象将其数据存储在连续的内存块中,并且在其中一个维度中是动态的。你能给我推荐一下怎么做吗?

的例子:

std::vector<std::array<int, 250>> pixelsMarker; 
// The array stores its data in a continuous block
// but the vector data not continuous, because
// an std::array is a complex object
std::vector<int[250]> pixelsMarker
// This is an invalid definition of a vector

为什么不创建自己的数据访问器并使用单个数组呢?

例如:

std::vector<int> myArray(250*100);

这里创建了100个数组,每个数组的大小为250(这是一个大小为250*100的数组)。要访问数组N中的元素,可以使用函数

int accessor(int N, int elementNum)
{
    return N*250 + elementNum;
}

这将给你N 'th数组中的元素elementNum

当然,您总是可以选择从std::vector继承或创建您自己的类来为您做这些。

这是一个可能的实现,在行为主配置中使用std::vector作为底层容器类型,其中可以在运行时使用semi_dynamic_matrix::insert_row, semi_dynamic_matrix::erase_row, semi_dynamic_matrix::pop_rowsemi_dynamic_matrix::rows_resize更改行数。

template<typename Ty,
    class Allocator = std::allocator<Ty>
> class semi_dynamic_matrix {
    class proxy_row_vector { // use to allow [][] usage on semi_dynamic_matrix objects
    public:
        proxy_row_vector(std::vector<Ty, Allocator>& _vec, std::size_t i, std::size_t cols) 
            : vec(_vec), row_ind(i), cols_(cols) {}
        const Ty& operator[](std::size_t j) const {
            return vec[row_ind*cols+j];
        }
        Ty& operator[](std::size_t j) {
            return vec[row_ind*cols+j];
        }
    private:
        std::vector<Ty, Allocator>& vec;
        std::size_t row_ind;
        std::size_t cols_;
    };
public:
    // PUBLIC TYPEDEFS
    typedef Ty value_type;
    typedef Ty& reference;
    typedef const Ty& const_reference;
    typedef Ty* pointer;
    typedef const Ty* const_pointer;
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;
    typedef Allocator allocator_type;
    typedef typename std::vector<Ty,Allocator>::iterator iterator;
    // and similar for const_iterator, reverse_iterator...
    // CONSTRUCTION/ASSIGNMENT
    // default constructor
    semi_dynamic_matrix() : semi_dynamic_matrix(Allocator()) {}
    explicit semi_dynamic_matrix(const Allocator& alloc)
        : mtx(alloc), rows_(0U), cols_(0U) {}
    // construct matrix of size rows*cols
    explicit semi_dynamic_matrix(size_type rows, size_type cols, const Allocator& alloc = Allocator())
        : mtx(rows*cols, alloc), rows_(rows), cols_(cols) {}
    // other constructors (copy, move, ...)
    // CAPACITY
    size_type rows() const noexcept { return rows_; }
    constexpr size_type columns() const noexcept { return cols_; }
    // ELEMENT ACCESS
    proxy_row_vector operator[](size_type i) const {
        return proxy_row_vector(mtx, i, cols_);
    }
    proxy_row_vector operator[](size_type i) {
        return proxy_row_vector(mtx, i, cols_);
    }
    // other accessors, e.g. at(), front(), ...
    // ITERATORS
    iterator begin() noexcept { return mtx.begin(); }
    iterator end() noexcept { return mtx.end(); }
    // similarly for cbegin(), cend(), rbegin(), ...
    // MODIFIERS
    iterator insert_row(size_type row_pos, const value_type& val) {
        return insert_row(row_pos, std::vector<value_type>(cols_, val));
    }
    iterator insert_row(size_type row_pos, const std::vector<value_type>& row_vec) {
        if (row_pos > rows_) throw std::out_of_range("message");
        if (row_vec.size() != cols_) throw std::invalid_argument("message");
        ++rows_;
        return mtx.insert(mtx.begin()+row_pos*cols_, row_vec.begin(), row_vec.end());
    }
    iterator insert_row(size_type row_pos, std::vector<value_type>&& row_vec =
        std::vector<value_type>()) {
        if (row_pos > rows_) throw std::out_of_range("message");
        if (row_vec.size() > cols_) throw std::invalid_argument("message");
        ++rows_;
        if (row_vec.size() < cols_) row_vec.resize(cols_);
        return mtx.insert(mtx.begin()+row_pos*cols_, std::make_move_iterator(
            row_vec.begin()), std::make_move_iterator(row_vec.end()));
    }
    iterator erase_row(size_type row_pos) {
        if (!(row_pos < rows_)) throw std::out_of_range("");
        --rows_;
        return mtx.erase(mtx.begin()+row_pos*cols_, mtx.begin()+cols_*(row_pos+1));
    }
    void pop_row() {
        for (size_type i = 0; i < cols_; ++i) mtx.pop_back();
        --rows_;
    }
    void rows_resize(size_type rows) {
        size_type tmp_rows = rows_;
        if (rows == rows_) return;
        if (rows > rows_) { // expand
            for (size_type i = 0; i < (rows_-tmp_rows); ++i)
                insert_row(rows_, std::move(std::vector<value_type>(cols_)));
        }
        else { // contract
            for (size_type i = 0; i < (tmp_rows-rows); ++i) pop_row();
        }
    }
private:
    std::vector<value_type, allocator_type> mtx;
    size_type rows_;
    size_type cols_;
};

然后你可以像这样使用

semi_dynamic_matrix<int> sdm(3,3); // create matrix of size 3x3
sdm.rows_resize(5); // resize matrix to 5x3
sdm.erase_row(0); // erase first row of matrix, size is now 4x3

底层迭代器类型仅使用std::vector迭代器,因此您可以在该类上执行任何典型的<algorithm>头(和其他)操作。

或者,如果你想要一个行和列都是动态的矩阵结构,那么考虑使用我之前创建的实现:dynamic_matrix .

为了使n维std::array成为连续块,std::array必须没有额外的开销。唯一应该在std::array中的数据是数组。关于数组的所有数据都由模板固定。

所以如果

std::array<std::array<int, 250>, 100> data;

是连续的,那么

std::vector<std::array<int, 250>> data;

也将是连续的

也就是说,我找不到(或解释)任何在最近的免费的标准草案(没有正式的副本),以保证一个实现不会添加一个或两个成员,只是为了破坏它的每个人,但为什么要这样做呢?