распределение векторов (или векторов векторов) динамически - PullRequest
18 голосов
/ 21 июля 2011

Мне нужно динамически выделить 1-D и 2-D массивы, размеры которых указаны во время выполнения.

Мне удалось «обнаружить» std::vector, и я думаю, что это соответствует моим целям, но яхотел бы спросить, является ли то, что я написал, правильным и / или может быть улучшено.

Вот что я делаю:

#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));

Ответы [ 7 ]

50 голосов
/ 21 июля 2011

Динамическое размещение массивов требуется, когда ваши измерения заданы во время выполнения, как вы обнаружили.

Однако std::vector уже является оболочкой вокруг этого процесса, поэтому динамическое распределениевекторы как двойной положительный.Это избыточно.

Просто напишите (C ++ 98):

#include <vector>

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

или (C ++ 11 и более поздние версии):

#include <vector>

using matrix = std::vector<std::vector<double>>;
matrix name(sizeX, std::vector<double>(sizeY));
9 голосов
/ 21 июля 2011

Вы связываете две проблемы: динамическое размещение и контейнеры с изменяемым размером. Вам не нужно беспокоиться о динамическом размещении, поскольку ваш контейнер уже делает это за вас, поэтому просто скажите это так:

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

Это сделает name объектом с автоматической продолжительностью хранения, и вы сможете получить доступ к его членам через name[i][j].

4 голосов
/ 21 июля 2011

То, что вы делаете, должно в основном работать, однако :

Как правило, не выделяет объекты динамически

Если вы хотите вектор, сделайте это:

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

не это:

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

Последний дает вам указатель, который вы должны удалить. Первый дает вам вектор, который, когда он выходит из области видимости, убирает за собой. (Внутренне, конечно, он динамически распределяет объекты, но хитрость в том, что это обрабатывается самим классом, и вам не нужно беспокоиться об этом в своем пользовательском коде).

2 голосов
/ 21 июля 2011

В то время как точки, сделанные другими ответами, были очень правильными (не динамически распределяйте вектор с помощью нового, а скорее позвольте вектору делать распределение), если вы думаете о терминах векторов и матриц (например, линейная алгебра), вы Возможно, стоит рассмотреть возможность использования библиотеки Eigen matrix.

2 голосов
/ 21 июля 2011

Это правильно, но можно сделать более эффективным.

Вы можете использовать расширенные многомерные массивы: http://www.boost.org/doc/libs/1_47_0/libs/multi_array/doc/user.html

Или вы можете реализовать свой собственный класс для него и самостоятельно выполнять индексацию. Возможно, что-то вроде этого (что не очень хорошо проверено):

#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_;
};
1 голос
/ 21 июля 2011

Вы не размещаете контейнеры динамически.Они могут автоматически управлять памятью, если сами не управляются вручную.

Вектор увеличивается, когда вы добавляете новые элементы с push_back (или insert), вы можете выбрать его размер в начале с аргументамив конструктор, и вы можете изменить его размер позже с помощью метода resize.

Создание вектора векторов ваших размеров с помощью конструктора выглядит следующим образом:

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

Это означает:size экземпляров std::vector<double>, каждый из которых содержит sizeY, удваивается (инициализируется до 0,0).

0 голосов
/ 21 июля 2011

Если вам не нужно изменять размеры массивов во время выполнения, вы можете просто использовать стандартные массивы (выделяемые во время выполнения)!

Однако, если вам нужноизмените размеры массивов во время выполнения, тогда вы можете использовать следующий (исправленный) код:

#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));

По сути, все, что я сделал, это удалил одну скобку (().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...