C++ vector with dynamic item size

2020-03-26 06:46发布

the C++ STL vector has a lot of decent properties, but only works when the size of each item is known at run-time.

I would like to have a vector class that features dynamic item size at run-time.

Background: My items consist of a sequence of integers and doubles; a sequence which is only known at run-time. It would suffice to have the vector be given the size of each item at run-time.

I am aware of possible workarounds, but these tend not to reflect the underlying idea of the algorithm, which is always a bad thing with regards to maintainance. Are there classes which provide such a convenience and work as efficient as one might expect?

EDIT:

This is not about item sizes varying throughout the array. It has nothing to do with that. It is at run-time deciding how large the items in the array are; i.e. a (very) weak form of dynamic typing, in contrast to static typing as used with templates.

Hence the initialization of the object should look like that:

DynamicVector V( lengthofvector, sizeofelement );

An application are simplicial meshes. The object $V$ contains items of fixed size or "type", each consisting of integers for the topological information and doubles for some geometric information. There might even come booleans into play, but this is irrelevant so far.

标签: c++ vector
9条回答
别忘想泡老子
2楼-- · 2020-03-26 07:20

If its just a sequence of int and double, then you can simply use:

 std::vector<double> sequence;

and then insert int and double into it. However, this approach doesn't keep track of the type of the items. If the type is critical for you, then probably the following may help you:

struct item
{
  union 
  {
     int i;
     double d;
  } data;
  char type; //store 0 for int, 1 for double;
};

std::vector<item> sequence;

Of course, this approach costs you atleast one extra byte per item, for storing the type of the item. You may want to use #pragma pack techniques to squeeze the extra padding.

Or even better would redesigning your code such that you've two sequences instead of one:

std::vector<int>     intSeq;
std::vector<double>  doubleSeq;
查看更多
等我变得足够好
3楼-- · 2020-03-26 07:24

Use std::vector where item is a wrapped smart pointer. The "item" class make a pointer look like a plain value :

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 {
   // ....
}
查看更多
Juvenile、少年°
4楼-- · 2020-03-26 07:24

I've seen this question before! Is there an STL container that stores an array of elements in contiguous memory where the element size is specified at runtime?

Guy wanted an "interleaved vector" (his word) that would hold dynamically sized objects, defined by a map of member types and offsets:

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;

And I came up with a (untested) class to handle that. The full code is in the link, but prototypes are:

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();
};

As a warning: it does rely on some behavior that I think is undefined, and in general, is a bad idea. Go with a vector of pointers.

查看更多
家丑人穷心不美
5楼-- · 2020-03-26 07:25

Create a class that contains three vectors: one for ints, one for doubles, and one that has an entry for each item to tell the type of the corresponding item and its index in the corresponding vector.

查看更多
欢心
6楼-- · 2020-03-26 07:31

You could use a vector of pointers to your sequence object - preferably smart pointers, to simplify memory management in the vector.

查看更多
SAY GOODBYE
7楼-- · 2020-03-26 07:33

I think the best way forward (in terms of performance and maintaiability) is a workaround, where you wrap std::vector and std::vector in two classes that interhit a common base class with an appropriate interface.

If you want it dynamic at runtime, that's how to do it properly. It'd also help you write efficient code for processing each item, as well as accessing each element simply (but slowly).

查看更多
登录 后发表回答