简体   繁体   English

动态分配向量(或向量的向量)

[英]allocating vectors (or vectors of vectors) dynamically

I need to dynamically allocate 1-D and 2-D arrays whose sizes are given at run-time.我需要动态分配大小在运行时给出的一维和二维 arrays。

I managed to "discover" std::vector and I think it fits my purposes, but I would like to ask whether what I've written is correct and/or can be improved.我设法“发现”了std::vector并且我认为它符合我的目的,但我想问一下我所写的内容是否正确和/或可以改进。

This is what I'm doing:这就是我正在做的事情:

#include <vector>

typedef std::vector< std::vector<double> > matrix;

//... various code and other stuff

std::vector<double> *name = new std::vector<double> (size);
matrix *name2 = new matrix(sizeX, std::vector<double>(sizeY));

Dynamically allocating arrays is required when your dimensions are given at runtime, as you've discovered.正如您所发现的,当您在运行时给出尺寸时,需要动态分配 arrays 。

However, std::vector is already a wrapper around this process, so dynamically allocating vectors is like a double positive.然而, std::vector已经是这个过程的一个包装器,所以动态分配向量就像一个双重肯定。 It's redundant.这是多余的。

Just write (C++98):只需编写 (C++98):

#include <vector>

typedef std::vector< std::vector<double> > matrix;
matrix name(sizeX, std::vector<double>(sizeY));

or (C++11 and later):或(C++11 及更高版本):

#include <vector>

using matrix = std::vector<std::vector<double>>;
matrix name(sizeX, std::vector<double>(sizeY));

You're conflating two issues, dynamic allocation and resizable containers.您将两个问题混为一谈,即动态分配和可调整大小的容器。 You don't need to worry about dynamic allocation, since your container does that for you already, so just say it like this:您无需担心动态分配,因为您的容器已经为您完成了,所以只需这样说:

matrix name(sizeX, std::vector<double>(sizeY));

This will make name an object with automatic storage duration, and you can access its members via name[i][j] .这将使name成为具有自动存储持续时间的 object,您可以通过name[i][j]访问其成员。

What you're doing should basically work, however :但是,您所做的基本上应该可以工作:

In general, don't dynamically allocate objects一般来说,不要动态分配对象

If you want a vector, do this:如果你想要一个向量,请执行以下操作:

std::vector<double> vec(size);

not this:不是这个:

std::vector<double>* vec = new std::vector<double>(size);

The latter gives you a pointer, which you have to delete.后者给你一个指针,你必须删除它。 The former gives you a vector which, when it goes out of scope, cleans up after itself.前者给你一个向量,当它离开 scope 时,它会自行清理。 (Internally, of course, it dynamically allocates objects, but the trick is that this is handled by the class itself, and you don't need to worry about it in your user code). (当然,它在内部动态分配对象,但诀窍是这是由 class 本身处理的,您无需在用户代码中担心它)。

It is correct but could be made more efficient.这是正确的,但可以提高效率。

You could use the boost multidimensional arrays: http://www.boost.org/doc/libs/1_47_0/libs/multi_array/doc/user.html您可以使用升压多维 arrays: http://www.boost.org/doc/libs/1_47_0/libs/multi_array/doc/user.ZFC35FDC70D5FC69D2369883A82EZ7

Or, you can implement your own class for it and handle the indexing yourself.或者,您可以为它实现自己的 class 并自己处理索引。 Perhaps something like this (which is not well tested):也许是这样的(没有经过很好的测试):

#include <vector>
#include <cassert>
template <typename T, typename A = std::allocator<T> >
class Array2d
{
public:
    typedef Array2d<T> self;
    typedef std::vector<T, A> Storage;

    typedef typename Storage::iterator       iterator;
    typedef typename Storage::const_iterator const_iterator;
    Array2d() : major_(0), minor_(0) {}
    Array2d(size_t major, size_t minor)
        : major_(major)
        , minor_(minor)
        , storage_(major * minor)
    {}

    template <typename U>
    Array2d(size_t major, size_t minor, U const& init)
        : major_(major)
        , minor_(minor)
        , storage_(major * minor, u)
    {
    }
    iterator begin()                { return storage_.begin(); }
    const_iterator begin() const    { return storage_.begin(); }
    iterator end()                  { return storage_.end(); }
    const_iterator end() const      { return storage_.end(); }
    iterator begin(size_t major) {
        assert(major < major_);
        return storage_.begin() + (major * minor_);
    }
    const_iterator begin(size_t major) const {
        assert(major < major_);
        return storage_.begin() + (major * minor_);
    }
    iterator end(size_t major) {
        assert(major < major_);
        return storage_.begin() + ((major + 1) * minor_);
    }
    const_iterator end(size_t major) const {
        assert(major < major_);
        return storage_.begin() + ((major + 1) * minor_);
    }
    void clear() {
        storage_.clear();
        major_ = 0;
        minor_ = 0;
    }
    void clearResize(size_t major, size_t minor)
    {
        clear();
        storage_.resize(major * minor);
        major_ = major;
        minor_ = minor;
    }
    void resize(size_t major, size_t minor)
    {
        if ((major != major_) && (minor != minor_))
        {
            Array2d tmp(major, minor);
            swap(tmp);

            // Get minimum minor axis
            size_t const dist = (tmp.minor_ < minor_) ? tmp.minor_ : minor_;
            size_t m = 0;
            // copy values across
            for (; (m < tmp.major_) && (m < major_); ++m) {
                std::copy(tmp.begin(m), tmp.begin(m) + dist, begin(m));
            }
        }
    }
    void swap(self& other)
    {
        storage_.swap(other.storage_);
        std::swap(major_, other.major_);
        std::swap(minor_, other.minor_);
    }
    size_t minor() const {
        return minor_;
    }
    size_t major() const {
        return major_;
    }
    T*       buffer()       { return &storage_[0]; }
    T const* buffer() const { return &storage_[0]; }
    bool empty() const {
        return storage_.empty();
    }
    template <typename ArrRef, typename Ref>
    class MajorProxy
    {
        ArrRef arr_;
        size_t major_;

    public:
        MajorProxy(ArrRef arr, size_t major)
        : arr_(arr)
        , major_(major)
        {}

        Ref operator[](size_t index) const {
            assert(index < arr_.minor());
            return *(arr_.buffer() + (index + (major_ * arr_.minor())));
        }
    };
    MajorProxy<self&, T&>
    operator[](size_t major) {
        return MajorProxy<self&, T&>(*this, major);
    }
    MajorProxy<self const&, T const&>
    operator[](size_t major) const {
        return MajorProxy<self&, T&>(*this, major);
    }
private:
    size_t major_;
    size_t minor_;
    Storage storage_;
};

While the points the other answers made were very correct (don't dynamically allocate the vector via new, but rather let the vector do the allocation), if you are thinking terms of vectors and matrices (eg linear algebra), you might want to consider using the Eigen matrix library.虽然其他答案的观点非常正确(不要通过 new 动态分配向量,而是让向量进行分配),但如果您正在考虑向量和矩阵的术语(例如线性代数),您可能想要考虑使用特征矩阵库。

Sometimes you don't want to fill your stack and your memory requirement is large.有时您不想填满您的堆栈并且您的 memory 要求很大。 Hence you may want to use vector> created dynamically especially while creating a table of a given row and col values.因此,您可能希望使用动态创建的 vector>,尤其是在创建给定行和列值的表时。

Here is my take on this in C++11这是我在 C++11 中对此的看法

int main() {
    int row, col;
    std::cin >> row >> col;
    auto *arr = new std::vector<std::vector<int>*>(row);
    for (int i=0; i<row; i++) {
        auto *x = new std::vector<int>(col, 5);
        (*arr)[i] = x;
    }

    for (int i=0; i<row; i++) {
        for(int j=0; j<col; j++) {
            std::cout << arr->at(i)->at(j) << " ";
        }
        std::cout << std::endl;
    }
    return 0;
}

You don't allocate containers dynamically.您不会动态分配容器。 They can automatically manage memory for you if they themselves are not manually managed.如果它们本身不是手动管理的,它们可以为您自动管理 memory。

A vector grows when you add new items with push_back (or insert ), you can choose its size from the start with arguments to the constructor, and you can resize it later with the resize method.当您使用push_back (或insert )添加新项目时,向量会增长,您可以从 arguments 开始到构造函数选择它的大小,稍后您可以使用resize方法调整它的大小。

Creating a vector of vectors with your sizes with the constructor looks like this:使用构造函数创建具有您的大小的向量的向量如下所示:

std::vector< std::vector<double> > matrix(size, std::vector<double>(sizeY));

This means: size instances of a std::vector<double> , each containing sizeY doubles (initialized to 0.0).这意味着: std::vector<double>size实例,每个包含sizeY双打(初始化为 0.0)。

 #include < iostream > 
 #include < vector >

 using namespace std;

int main(){

vector<int>*v = new vector<int>();   // for 1d vector just copy paste  it

v->push_back(5);
v->push_back(10);
v->push_back(20);
v->push_back(25);

for(int i=0;i<v->size();i++){
    cout<<v->at(i)<<" ";
}
cout<<endl;

delete v;

system("pause");
return 0;

     }

If you don't need to resize the array sizes at run time, then you can just use standard arrays (allocated at runtime)!如果您不需要在运行时调整数组大小,那么您可以使用标准 arrays(在运行时分配)!

However, if you do need to resize arrays at runtime, then you can use the following (revised) code:但是,如果您确实需要在运行时调整 arrays 的大小,则可以使用以下(修改后的)代码:

#include <vector>

typedef std::vector< std::vector<double> > matrix;

//... various code and other stuff

std::vector<double> *name = new std::vector<double> (size);

matrix *name2 = new matrix(sizeX, std::vector<double>(sizeY));

In essence, all I've done is remove a single bracket ( ( ).本质上,我所做的只是删除一个括号 ( ( )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM