3

Performance is crucial in my application

I need something that works like std::experimental::dynarray, so an array which size is decided at runtime.

So I thought about using a wrapper class for std::vector, giving all its features, but without the possibility to call resize, reserve or push_back. In few words, all the methods to change its size (please remind me if I missed some of them).

So I started writing this class:

CCVector.hpp:

template <typename T>
class CCVector{
public:
    CCVector(size_t size);
    T &operator[](typename std::vector<T>::size_type idx);
private:
    std::vector<T> v;
};

CCVector.cpp:

template<typename T>
CCVector<T>::CCVector(size_t size) : v(size){}
template<typename T>
T& CCVector<T>::operator[](typename std::vector<T>::size_type idx){
    return  v[idx];
}

But I this point I thought I have to re-implement every method of std::vector that I need! For example begin, end, size etc, and I don't know how to implement all of them...Besides, this is really bad for maintenance: as soon as I need a new method from std::vector I need to re-implement it in CCVector.

All of this because I want fixed size arrays at runtime. How can I solve this without using the non-standard std::experimental::dynarray?

Bruno Rijsman
  • 3,715
  • 4
  • 31
  • 61
justHelloWorld
  • 6,478
  • 8
  • 58
  • 138
  • 2
    Just inherit from std::vector, then do a using statement for each function that you wish to expose in you public section. Then do a using statement in the private section for all of the functions you want to disable. – Alex Zywicki Mar 08 '17 at 13:26
  • 1
    You could also just use the code from [here](http://stackoverflow.com/a/15832431/4342498) – NathanOliver Mar 08 '17 at 13:27
  • @Ðаn It's funny. Even though the title says not to the very first answer(highest vote and accepted) says there is nothing wrong with it. – NathanOliver Mar 08 '17 at 13:31
  • 2
    http://stackoverflow.com/a/4353333/1865694 Did you read the accepted answer? That says "Actually, there is nothing wrong with public inheritance of std::vector. If you need this, just do that..." – Alex Zywicki Mar 08 '17 at 13:31
  • If the standard containers were truly not meant to be inherited from then I would imagine that the standard would specify so and have them marked as final using the fancy keyword that we were provided with for this exact purpose. Though I will admit that the standard is not always as thorough as it could be. – Alex Zywicki Mar 08 '17 at 13:46
  • This is new to me, so I'm curious, what's the difference between `dynarray` and `std::array`? – Mine Mar 08 '17 at 14:00
  • @Mine std::array is a thin wrapper around T[n], so includes the array within the object (and so must be copied if passed by value). Dynarray has a dynamically allocated pointer to the T[n] (and so can be efficiently moved). – Mike Vine Mar 08 '17 at 14:05
  • I forgot to write that performance are crucial in my application, condsider that :) – justHelloWorld Mar 08 '17 at 14:08
  • @Ðаn But most of the standard library was designed quite recently, or at least revised recently. With the addition of `constexpr`, `noexcept` and other language features. Most of the standard library containers were revised to support those features... The `final` keyword came along with c++11 and yet here we are yet we have already seen c++14 and now we nearly have c++17 which have made no effort to add such a change. So I would argue that it was not found to be a big enough issue to warrant adding the `final` specification to the standard library containers. – Alex Zywicki Mar 08 '17 at 14:59
  • @Ðаn I suppose my point was that they could have opted for that breaking change if inheriting from the standard containers was such a big issue. – Alex Zywicki Mar 08 '17 at 15:09

3 Answers3

5

Use private inheritance and then import the functions you want using the using declaration to introduce the names you want into your class.

template<class T>
class MyVector : private std::vector<T>
{
public:
    using std::vector<T>::end;
    // etc
};

(With private inheritance you don't get the issue with vector not having a virtual destructor which is the reason most people don't like inheriting from standard containers)

Mike Vine
  • 9,468
  • 25
  • 44
0

You are right that std::vector has quite a few member functions that you need to expose to the outside, but there are not thaaat many. For example, see here http://www.cplusplus.com/reference/vector/vector/

Furthermore, you do not need to (and should not) reimplement std::vector on your own - relying on tested, fast code like your STL is almost always the better option.

So, instead of reimplementing, simply "forward" the functions to the outside, like so:

iterator begin()
{
   return v.begin();
}

This is a bit of boilerplate code, but if you do this once for the non-resizing functions of std::vector, you are done.

Edit:

Also, do not inherit from std::vector. This is a bad idea for many reasons.

Okay, I was a bit quick here, sorry for that. As the comments, and this post suggest, inheriting from an STL container is not inherently bad. Particularly if you use private inheritance, it might just be a valid solution for the given task.

Community
  • 1
  • 1
luc
  • 322
  • 1
  • 15
  • 2
    Inheriting from vector is a bad idea for many reason? Reasons that nobody seems to want to explain in more detail than "don't do it l, it's bad" – Alex Zywicki Mar 08 '17 at 13:37
  • 1
    @AlexZywicki Quite. The main reason I've seen is virtual destruction but that's avoidable. Other things like 'users wont know how to use the class' is not specific to this. luc If you _list_ the issues with inheriting froms tandard containers then OP can make their own decision to whether its applicable in their case. – Mike Vine Mar 08 '17 at 13:39
  • @AlexZywicki I don't know of *many* reasons, but I know that *public* inheritance is dangerous because it *implies* that `std::unique_ptr> ptr = new derived` is OK, when it actually has UB. – eerorika Mar 08 '17 at 13:40
  • 1
    @user2079303 Sure you can misuse it. But this isn't a problem with inheriting from standard classes - I can design a system with base and derived classes and no virtual destructors which you can equally misuse by deleting a Derived via a pointer to Base. And before you say how awful that design is note that shared_ptr deliberately goes out of its way to support this: shared_ptr(new Derived()) will always destruct via a pointer to Derived even if Derived has no virtual destructor (magic!). – Mike Vine Mar 08 '17 at 13:44
  • @MikeVine but you don't want overhead of shared pointer when you don't need shared ownership. Always using shared pointer just in case somebody might assign a derived pointer is silly in my opinion. To me, saying that "publicly inheriting a class with non virtual destructor is OK because you *can* use shared pointers" is just as silly as saying "using bare instead of smart pointers is OK, because you can follow the rule of 5". – eerorika Mar 08 '17 at 13:50
  • 1
    @user2079303 My point was that its not an unreasonable thing to have (base classes with no virtual destructors) under certain circumstances. Not that shared_ptr was the answer to all the worlds ills. – Mike Vine Mar 08 '17 at 13:53
  • 2
    Anyone dynamically allocating a class whose sole job it is to manage a dynamic allocation is either doing something stupid and/or should be qualified to notice the lack of virtual destructor. You can't fix stupid. – Yakk - Adam Nevraumont Mar 08 '17 at 13:57
0

Privately inheriting std::vector is as proposed in the other answer is one approach.

There is some memory overhead for using resizable container where a non-resizable would suffice. std::vector is typically around ~4 x size of a data pointer. You can store a pointer to data + length in half of that:

template<class T>
class dynarray
{
    std::unique_ptr<T[]> data;
    T*                   end; // or size_t size

    //TODO functions
};

The downside obviously is that you must re-implement all of the boilerplate, that you could otherwise inherit from std::vector. That said, all of the boilerplate is quite trivial - there is just lots of it.

eerorika
  • 232,697
  • 12
  • 197
  • 326