【问题标题】:C++ vector with dynamic item size具有动态项目大小的 C++ 向量
【发布时间】:2011-09-13 06:36:13
【问题描述】:

C++ STL 向量有很多不错的属性,但只有在每个项目的大小在运行时已知时才有效。

我想要一个在运行时具有动态项目大小的矢量类。

背景:我的项目由一系列整数和双精度数组成;仅在运行时已知的序列。在运行时为向量提供每个项目的大小就足够了。

我知道可能的解决方法,但这些方法往往不能反映算法的基本思想,这对于维护而言总是一件坏事。有没有像人们期望的那样提供如此便利和高效工作的类?

编辑:

这与整个数组中的项目大小不同。它与此无关。在运行时决定数组中的项目有多大;即动态类型的(非常)弱形式,与模板中使用的静态类型形成对比。

因此对象的初始化应该如下所示:

DynamicVector V( lengthofvector, sizeofelement );

应用程序是简单的网格。对象 $V$ 包含固定大小或“类型”的项目,每个项目都包含用于拓扑信息的整数和用于某些几何信息的双精度数。甚至可能会出现布尔值,但到目前为止这无关紧要。

【问题讨论】:

  • 听起来你想要一个向量的向量。在 C++ 中没有办法拥有不同大小的对象的集合。
  • 我认为指针向量是您不想使用的解决方法之一?
  • @Neil 这看起来像是对我的回答。
  • dynamic item size 是什么意思?项目本身是容器,还是您的意思是 sizeof(item) 会有所不同?
  • 所以你的向量中的每个项目都是一个序列?或者向量包含整数或双精度项的序列?人们期望这样的数据结构有多高效?

标签: c++ vector


【解决方案1】:

问题是,如果您没有办法将每个项目的大小存储在向量中,您将永远无法取回数据。

将所有项目存储为double 怎么样?这大大简化了事情。

您也可以考虑boost::variant。

编辑:但是你真的能进一步解释为什么你想在同一个序列中存储两种不同的类型吗?这有时表明底层设计需要进一步思考。

【讨论】:

    【解决方案2】:

    您可以使用指向序列对象的指针vector - 最好是智能指针,以简化向量中的内存管理。

    【讨论】:

      【解决方案3】:

      如果它只是int和double的序列,那么你可以简单地使用:

       std::vector<double> sequence;
      

      然后将int 和double 插入其中。但是,这种方法不会跟踪项目的 type。如果 type 对您很重要,那么以下内容可能会对您有所帮助:

      struct item
      {
        union 
        {
           int i;
           double d;
        } data;
        char type; //store 0 for int, 1 for double;
      };
      
      std::vector<item> sequence;
      

      当然,这种方法至少每个项目花费一个额外字节,用于存储项目的类型。您可能想使用#pragma pack 技术来压缩额外的填充。

      或者更好的是重新设计你的代码,这样你就有两个序列而不是一个:

      std::vector<int>     intSeq;
      std::vector<double>  doubleSeq;
      

      【讨论】:

      • 它可能而且几乎总是会超过一个额外的字节:您忘记考虑填充。
      【解决方案4】:

      vector 表示内存中的一个连续数组。这是有效的,因为它可以使用指针算法通过索引直接访问元素。但是这样做意味着所有元素都具有相同的大小,并且在构建向量之前要知道这个大小。

      根据您的需要,可以使用双链表的元素指针向量。指针向量几乎和向量一样快。它只需要一种模式遵从。

      如果您的整数和双精度数大小相同(例如 64 位),您可以使用联合将每个项目作为整数或双精度数来访问。但是您需要一种方法来了解每个元素应该是什么。

      【讨论】:

        【解决方案5】:

        如果您不想求助于解决方法,我认为您应该考虑对那些“动态大小的项目”进行抽象。它的设计应该牢记它必须在 STL 向量中使用(然后必须保证一些必要条件),以便您最终可以编写如下内容:

        std::vector<DynamicSizedItem> myVector;
        

        【讨论】:

          【解决方案6】:

          创建一个包含三个向量的类:一个用于整数,一个用于双精度,一个为每个项目都有一个条目,以告知相应项目的类型及其在相应向量中的索引。

          【讨论】:

            【解决方案7】:

            使用 std::vector 其中 item 是一个包装的智能指针。 "item" 类使指针看起来像一个普通值:

            class item {
            private:
                boost:unique_ptr<base> p;
            public:
                // ...
                public item(item that);
            
                public int someFunction() {
                   // Forwarded
                   return p->somefunction();
                }
            };
            
            class base {
                virtual ~base();
                // This is needed in order to implement copy of the item class
                virtual base* clone();
            };
            
            public item::item(item that) : p(that.p.clone()) {}
            
            class some_real_type() : public base {
               // ....
            }
            

            【讨论】:

              【解决方案8】:

              我认为最好的解决方法(就性能和可维护性而言)是一种变通方法,将 std::vector 和 std::vector 包装在两个类中,这两个类通过适当的接口与公共基类交互。

              如果您希望它在运行时动态,那就是正确的做法。它还可以帮助您编写高效的代码来处理每个项目,以及简单地(但缓慢地)访问每个元素。

              【讨论】:

                【解决方案9】:

                我以前见过这个问题! Is there an STL container that stores an array of elements in contiguous memory where the element size is specified at runtime?

                Guy 想要一个“交错向量”(他的话),它可以保存动态大小的对象,由成员类型和偏移量的映射定义:

                typedef Toffset uint; //byte offset;
                typedef Ttype   uint; //enum of types
                typedef std::pair<Toffset,Ttype> member;
                typedef std::unordered_map<std::string, member> memberdefs;
                

                我想出了一个(未经测试的)类来处理这个问题。完整的代码在链接中,但原型是:

                class interleaved_vector {
                    const char* buffer;
                    size_t count;
                    size_t size;
                    std::shared_ptr<memberdefs> members;
                public: 
                    class dynamic_object {
                        const char* buffer;
                        std::shared_ptr<memberdefs> members;
                        friend interleaved_vector;
                        dynamic_object(const char* buffer_, std::shared_ptr<memberdefs> members_);
                        dynamic_object& operator=(const dynamic_object& b) = delete;
                    public:
                        dynamic_object(const dynamic_object& b) ;
                        template <class T>
                        T get(const std::string& member) const;
                        template <>
                        T* get<T*>(const std::string& member) const;
                        void* operator[](const std::string& member) const;
                    };
                    interleaved_vector(const char* buffer_, size_t count_, size_t size_, const memberdefs& members_);
                    dynamic_object get(size_t index) const;
                    dynamic_object operator[](size_t index) const;
                    size_t size();
                };
                

                作为警告:它确实依赖于一些我认为未定义的行为,一般来说,这是一个坏主意。使用指针向量。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-07-19
                  • 1970-01-01
                  • 2011-03-27
                  • 1970-01-01
                  • 2019-06-27
                  • 1970-01-01
                  相关资源
                  最近更新 更多