2

I want to create a container that provides all of the same functionality as a std::vector but with the caveat that you cannot add anymore elements once the vector reaches a specified size.

My first thought was to inherit from std::vector and do something like

template <typename T, unsigned int max>
class MyVector : public std::vector<T> {
  public:
    // override push_back, insert, fill constructor, etc...
    // For example:
    virtual void push_back(const T& var) override {
      if (this.size() < max) vec.push_back(var);
    }
};

But then I learned that inheriting STL containers is bad.

Second thought was to create a wrapper class, i.e.

template <typename T, unsigned int max>
class MyVector {
  private:
    std::vector<T> vec;
  public:
    // Wrappers for every single std::vector function...
    iterator begin() { return vec.begin(); }
    const_iterator begin() const { return vec.begin(); }
    //and on and on and on...etc.
};

But this smells bad to me. Seems very difficult to maintain.

Am I missing something obvious, should I try an alternative approach?

  • 2
    Inheriting from standard containers is only bad if you don't know what you are doing. – Ted Lyngmo Jun 11 '21 at 22:05
  • 4
    Inherit privately. – François Andrieux Jun 11 '21 at 22:06
  • 1
    Be aware that the maximum size of a `std::vector` may be quite different than the available memory size (available to your process). – Thomas Matthews Jun 11 '21 at 22:08
  • 1
    Concerning your second thought: when you design a container you decide what operations it should support, and you implement those operations. For a vector-like class, much of the bookkeeping has already been done for you, and many of the functions that your wrapper class provides simply forward to a stored data member of type `vector`. They're trivial to write and to maintain. A few need more than what the vector provides, and you write code accordingly. You could, of course, write your entire class from scratch, and that would be much more difficult to maintain. – Pete Becker Jun 11 '21 at 22:11
  • Why not use a non-member function taking the vector and the element as usual parameters and the max as a template parameter (or usual...)? – prog-fh Jun 11 '21 at 22:12
  • @prog-fh These vectors are exposed through an API. Currently, users can take them past a set limit causing segmentation issues further down the road. I'm trying to cut this problem off at the source instead of adding length checks everywhere the vectors are used, which would be even harder to maintain. – TenderShortGoldenRetriever Jun 11 '21 at 22:15
  • @FrançoisAndrieux private inheritance seems most attractive currently. – TenderShortGoldenRetriever Jun 11 '21 at 22:16
  • 1
    @Job_September_2020 Asker linked to that exact question in the original question, he's aware of it. – Nathan Pierson Jun 11 '21 at 22:27
  • 1
    @DevinTrowbridge -- [Boost already has done this](https://www.boost.org/doc/libs/1_76_0/doc/html/boost/container/static_vector.html). You can see how they implemented this, or just use boost (this particular class is header-only, so no external linking of a library is required). – PaulMcKenzie Jun 12 '21 at 00:17
  • If you are trying to stop other developers from resizing a `std::vector` past a certain size, then you need to somehow convince/force them to use length checks. There isn't some way to magically force that on them (e.g. by deriving a class from `std::vector` or (better) containing it in another class that enforces constraints) if they use `std::vector` and its operations directly. Also, if exceeding some reduced size limit on a `std::vector` causes "segmentation issues" then some other code (e.g. which is using vector elements out of bounds) is the culprit - you need to find/fix that code – Peter Jun 12 '21 at 01:55
  • @Peter I ended up going with your suggestion. I don't want to remove the features of std::vector from my users. I am just length checking the vectors elsewhere, dropping excess elements, and warning devs that the elements were dropped. I think this offers the most familiar API at the cost of maintainability on my end. – TenderShortGoldenRetriever Jun 14 '21 at 17:12

1 Answers1

2

How can I create a vector with a maximum length?

You cannot do that with std::vector. You can however refrain from inserting any elements after you reach some limit. For example:

if (v.size() < 10) {
    // OK, we can insert
}

I want to create a container that provides all of the same functionality as a std::vector but with the caveat that you cannot add anymore elements once the vector reaches a specified size.

That, you can do.

virtual void push_back(const T& var) override {

std::vector::push_back isn't virtual, so you may not override it.

Also, I recommend considering whether the push back should be silently ignored in the case max is reached.

But then I learned that inheriting STL containers is bad.

To be more specific, publicly inheriting them is a bit precarious.

Using private inheritance, you can use using to pick the members that you wish to delegate directly, and implement the differing members manually.

Seems very difficult to maintain.

The standard library doesn't change very often, and the vector class hasn't changed much so far, and changes have been quite simple, so "very difficult" is debatable - although subjective of course.

You could use meta-programming to make it maintainable. But that may be bit of an over-engineered approach.

cigien
  • 57,834
  • 11
  • 73
  • 112
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • This does answer the question that I asked. I will mention that I ended up keeping the vanilla `std::vector`s and length check them via a free-function. More difficult on my end to maintain, but I think its worth having the optimizations and familiarity the STL offers. – TenderShortGoldenRetriever Jun 15 '21 at 14:25