【问题标题】:allocating vectors (or vectors of vectors) dynamically动态分配向量(或向量的向量)
【发布时间】:2011-07-21 11:58:21
【问题描述】:

我需要动态分配大小在运行时给出的一维和二维数组。

我设法“发现”了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));

【问题讨论】:

    标签: c++ vector


    【解决方案1】:

    正如您所发现的,当您的维度在运行时给出时,需要动态分配数组。

    然而,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));
    

    【讨论】:

      【解决方案2】:

      您将两个问题混为一谈,即动态分配和可调整大小的容器。您不必担心动态分配,因为您的容器已经为您完成了,所以只需这样说:

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

      这将使name成为具有自动存储期限的对象,您可以通过name[i][j]访问其成员。

      【讨论】:

      • 首先:感谢您的回复。那么,为了完全确定我理解你的答案,你的意思是我不需要 的“新”?
      • 简短回答:确实,你没有。中等答案:如果您习惯性地使用 C++,那么无论如何您都不应该说 new(除了在 unique_ptr 的构造函数内部可能例外)。
      • 好的,中等答案对我来说越来越难了,你能给我一个参考吗?只是为了理解“惯用”是什么意思,或者为什么我不应该使用new
      • 不确定参考资料,任何现代的、好的 C++ 教科书我想...关键是您不应该手动管理资源,而应该始终使用专用的资源管理容器。如果你有一个具体的情况,你想说new,发布它并询问如何做得更好。
      • @Federico - 与其说是“不应该”,倒不如说你几乎必须在 C++ 代码中使用 new 和 delete。库设施,如 std::vector 和 std::string 会为您处理这些。
      【解决方案3】:

      你正在做的应该基本上可以工作,然而

      一般来说,不要动态分配对象

      如果你想要一个向量,这样做:

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

      不是这个:

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

      后者给你一个指针,你必须删除它。前者为您提供了一个向量,当它超出范围时,它会自行清理。 (当然,它在内部动态分配对象,但诀窍是由类本身处理,您无需在用户代码中担心它)。

      【讨论】:

      • 如果您运行的是单线程应用程序,当然可以。在内存分配方面,多线程引入了一套全新的注意事项。
      • @pg1989:您是否建议在多线程应用程序中,您应该尝试让不同的线程执行分配和释放?不,在多线程程序中,同样的规则适用,更是如此
      • 不,我更多的是指共享资源的并发访问。可能是我措辞不对。确实,在惯用的 c++ 中,您永远不应该显式调用 new。然而,你仍然需要考虑你正在操作的对象,因为如果一个线程试图访问一个已经被销毁的对象,就会发生不好的事情。
      • 您需要考虑所有权和寿命,是的。这总是正确的,不管你有多少线程,它与newdelete 无关,也不是多线程独有的。
      • @jalf 假设,我正在实现一个vector to vector 场景,基本上是一个具有未知行和列的矩阵,我正在执行 v[a].push_back(b) (treating a &amp; b as ints)。我应该如何声明向量 v 而不在编译时给出固定长度?因为,直接写v[a].push_back(b)就是给我segmentation fault
      【解决方案4】:

      这是正确的,但可以提高效率。

      您可以使用 boost 多维数组: 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_;
      };
      

      【讨论】:

        【解决方案5】:

        虽然其他答案的观点非常正确(不要通过 new 动态分配向量,而是让向量进行分配),但如果您正在考虑向量和矩阵的术语(例如线性代数),您可能要考虑使用 Eigen 矩阵库。

        【讨论】:

          【解决方案6】:

          您不会动态分配容器。如果它们本身不是手动管理的,它们可以自动为您管理内存。

          当您使用push_back(或insert)添加新项目时,向量会增长,您可以从构造函数的参数开始选择它的大小,稍后您可以使用resize 方法调整它的大小。

          使用构造函数创建具有您的大小的向量的向量如下所示:

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

          这意味着:std::vector&lt;double&gt;size 实例,每个包含 sizeY 双精度(初始化为 0.0)。

          【讨论】:

            【解决方案7】:

            有时你不想填满你的堆栈并且你的内存需求很大。因此,您可能希望使用动态创建的 vector>,尤其是在创建给定行和列值的表时。

            这是我在 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;
            }
            

            【讨论】:

              【解决方案8】:
               #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;
              
                   }
              

              【讨论】:

                【解决方案9】:

                如果您不需要在运行时调整数组大小,那么您可以使用标准数组(在运行时分配)!

                但是,如果您确实需要在运行时调整数组大小,则可以使用以下(修改后的)代码:

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

                本质上,我所做的只是删除一个括号 (()。

                【讨论】:

                • 是的,bracket 是一个错字,我也从原帖中删除了它:P
                猜你喜欢
                • 2020-06-15
                • 1970-01-01
                • 2011-07-16
                • 2020-06-20
                • 2013-12-08
                • 1970-01-01
                • 1970-01-01
                • 2016-08-11
                • 2014-06-16
                相关资源
                最近更新 更多