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?
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.
Related
Is there an alternative to resize() of an std::vector, which only allows the increase the size of the vector
std::vector v;
v.resize(10);
v.resize(5);
--> v.size() == 5, but I like its length to stay at 10 and moreover I like its data not to be (potentially) deleted.
I could use
std::vector v;
v.resize(std::max(v.size(),10));
v.resize(std::max(v.size(),5));
This is a bit ugly. Is there a more elegant way?
This seems like a strange request. It would be interesting to know why you want this infinitely expanding vector. One solution (as suggested here) would be to inherit from std::vector privately and implement your own resize, ie something like:
template <class T> // Can also forward the allocator if you want
class InfiniteResizeVector: private std::vector<T>
// The private is very important, std::vector has no virtual destructor, so you
// cannot allow someone to reference it polymorphically.
{
public:
using vector::push_back;
using vector::operator[];
... // For all the functions you need
void resize(size_t new_size) {
vector::resize(std::max(size(),new_size));
}
};
Usage would then just be v.resize(5); like you asked for. Make sure you read some of the other answers from the link above. This is a very unusual thing to do, unless this is something you will use all the time it is certainly not worth making your own independent type.
Fantastic Mr Fox offers to solve this problem through inheritance and rewriting, but it's possible to solve this problem through combination composition, but it's probably a little more troublesome, and here's my example.
template<typename T>
class OnlyGrowVector {
public:
using size_type = typename std::vector<T>::size_type;
void push_back(T&& t)
{
m_vector.push_back(std::forward<T>(t));
}
T& operator[](size_type idx)
{
return m_vector[idx];
}
... // for what you need
void resize(size_type size)
{
m_vector.resize(std::max(m_vector.size(), size));
}
private:
std::vector<T> m_vector;
};
I have an application that I want to minimize dynamic allocation for efficiency.
I'm leaning forward using boost::static_vector in one of my classes for that reason. I'm not sure yet exactly how big my array will need to be to accommodate most situations but there are always exceptions...
Instead of discarding the input that would require more space than what my static_vector can store, I would like to fall back on std::vector to handle those exceptions.
A pattern that I commonly use in my classes design, is that I provide its input to the constructor to populate its container, then I provide a getter function that returns a const reference to the inner container.
The possibility that the class might use one or another container is causing a mental blind spot in me.
What would be the best way to offer access to the class elements?
I have come up with few ideas but none are truly satisfactory...
Make my class a container using the proxy/facade pattern
I'm too lazy for doing that and this is not practical if I want to apply this static_vector/vector solution everywhere...
Place the burden on the class user
ie.
void foo(HybridContainerObj &ojb) {
if (obj.IsUsingStaticVector()) {
const boost::static_vector<SomeElem> &vRef = obj.getStaticVec();
}
else {
const std::vector<SomeElem> &vRef = obj.getVec();
}
}
I doesn't feel right to me...
Modify boost::static_vector to do exactly what I have in mind
So far, this is my favorite solution...
Use some C++ magic that I am unaware of
Since both container classes do implement the same STL container concept, I wish that something along the lines would be possible:
const auto &vecRef = obj.getVec();
but AFAIK, this isn't possible... right?
So, I'm here to see what others think of that problem and if someone would have an elegant proposal to present the class used container elements to its users...
Greetings
boost::small_vector may be the combination you are looking for. From https://www.boost.org/doc/libs/1_60_0/doc/html/boost/container/small_vector.html:
small_vector is a vector-like container optimized for the case when it
contains few elements. It contains some preallocated elements
in-place, which can avoid the use of dynamic storage allocation when
the actual number of elements is below that preallocated threshold.
What you want is an "abstraction" over both std::vector and boost::static_vector, depending on what operations you want to do on the abstraction, you have different possibilities:
If you want const-access to the container, you can simply use a class that would wrap a raw array since both std::vector and boost::static_vector use a raw array internally. Fortunately for you, C++20 already has such class: std::span (if you don't have C++20, you can use the one from the GSL). This is the preferred option since it is probably completely transparent in term of performance and the interface of std::span is close to the read-only operations of std::vector or boost::static_vector.
If you want more operations (e.g. being able to push_back, etc.), you'd need a proper abstraction similar to what std::function does for functor objects, which requires a lot more work:
namespace details {
template <class T>
struct container_wrapper {
// All the operations you need.
virtual void push_back(T const& t) = 0;
};
template <class T>
class vector_wrapper: public container_wrapper<T> {
std::vector<T> *m_Vec;
public:
vector_wrapper(std::vector<T> &vec) : m_Vec{&vec} { }
void push_back(T const& t) override {
m_Vec->push_back(t);
}
};
template <class T>
struct static_vector_wrapper: public container_wrapper<T> {
boost::static_vector<T> *m_Vec;
public:
vector_wrapper(boost::static_vector<T> &vec) : m_Vec{&vec} { }
void push_back(T const& t) override {
m_Vec->push_back(t);
}
};
}
template <class T>
class my_container {
std::unique_ptr<details::container_wrapper> m_Wrapper;
public:
my_container(std::vector<T> &vec) :
m_Wrapper(std::make_unique<details::vector_wrapper<T>>(vec)) { }
my_container(boost::static_vector<T> &vec) :
m_Wrapper(std::make_unique<details::static_vector_wrapper<T>>(vec)) { }
};
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?
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)
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.
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.
I'm porting some Fortran90 code to C++ (because I'm stupid, to save the "Why?!").
Fortran allows specification of ranges on arrays, in particular, starting at negative values, eg
double precision :: NameOfArray(FirstSize, -3:3)
I can write this in C++ as something like
std::array<std::array<double, 7>, FirstSize> NameOfArray;
but now I have to index like NameOfArray[0:FirstSize-1][0:6]. If I want to index using the Fortran style index, I can write perhaps
template <typename T, size_t N, int start>
class customArray
{
public:
T& operator[](const int idx) { return data_[idx+start]; }
private:
std::array<T,N> data_;
}
and then
customArray<double, 7, -3> NameOfArray;
NameOfArray[-3] = 5.2;
NameOfArray[3] = 2.5;
NameOfArray[4] = 3.14; // This is out of bounds,
// despite being a std::array of 7 elements
So - the general idea is "Don't inherit from std::'container class here'".
My understanding is that this is because, for example, std::vector does not have a virtual destructor, and so should not (can not?) be used polymorphically.
Is there some other way I can use a std::array, std::vector, etc, and get their functions 'for free', whilst overriding specific functions?
template<typename T, size_t N>
T& std::array<T,N>::operator[](const int idx) { ... };
might allow me to override the operator, but it won't give me access to knowledge about a custom start point - making it completely pointless. Additionally, if I were to optimistically think all my customArray objects would have the same offset, I could hardcode that value - but then my std::array is broken (I think).
How can I get around this? (Ignoring the simple answer - don't - just write myArray[idx-3] as needed)
There's no problem with inheriting standard containers. This is only generally discouraged because this imposes several limitations and such an inheritance is not the way how inheritance was originally predicted in C++ to be used. If you are careful and aware of these limitations, you can safely use inheritance here.
You just need to remember that this is not subclassing and what this really means. In particular, you shouldn't use pointers or references to the object of this class. The problem might be if you pass a value of MyVector<x>* where vector<x>* was expected. You should also never create such objects as dynamic (using new), and therefore also delete these objects through the pointer to the base class - simply because destructor call will not forward to your class's destructor, as it's not virtual.
There's no possibility to prevent casting of the "derived pointer" to the "base pointer", but you can prevent taking a pointer from an object by overloading the & operator. You can also prevent creating objects of this class dynamically by declaring an in-class operator new in private section (or = delete should work as well).
Don't also think about private inheritance. This is merely like containing this thing as a field in private section, except the accessor name.
A range converter class could be the solution although you would need to make it yourself, but it would allow you to get the range size to initialize the vector and to do the conversion.
Untested code:
struct RangeConv // [start,end[
{
int start, end;
RangeConv(int s, int e) : start(s), end(e) { }
int size() const { return end - start; }
int operator()(int i) { return i - start; } // possibly check whether in range
}
RangeConv r(-3, 3);
std::vector<int> v(r.size());
v[r(-3)] = 5;
so should not (can not?) be used polymorphically.
Don't give up too soon. There are basically two issues to consider with inheritance in C++.
Lifetime
Such objects, derived classes with non-virtual destructors in the base, can be used safely in a polymorphic fashion, if you basically follow one simple rule: don't use delete anywhere. This naturally means that you cannot use new. You generally should be avoiding new and raw pointers in modern C++ anyway. shared_ptr will do the right thing, i.e. safely call the correct destructor, as long as you use make_shared:
std:: shared_ptr<Base> bp = std:: make_shared<Derived>( /* constructor args */ );
The type parameter to make_shared, in this case Derived, not only controls which type is created. It also controls which destructor is called. (Because the underlying shared-pointer object will store an appropriate deleter.)
It's tempting to use unique_ptr, but unfortunately (by default) it will lead to the wrong deleter being used (i.e. it will naively use delete directly on the base pointer). It's unfortunate that, alongside the default unique_ptr, there isn't a much-safer-but-less-efficient unique_ptr_with_nice_deleter built into the standard.
Polymorphism
Even if std::array did have a virtual destructor, this current design would still be very weird. Because operator[] is not virtual, then casting from customArray* to std:: array* would lead to the wrong operator[]. This isn't really a C++-specific issue, it's basically the issue that you shouldn't pretend that customArray isa std:: array.
Instead, just decide that customArray is a separate type. This means you couldn't pass an customArray* to a function expecting std::array* - but are you sure you even want that anyway?
Is there some other way I can use a std::array, std::vector, etc, and get their functions 'for free', whilst overloading specific functions?
This is a good question. You do not want your new type to satisfy isa std::array. You just want it to behave very similar to it. As if you magically copied-and-pasted all the code from std::array to create a new type. And then you want to adjust some things.
Use private inheritance, and using clauses to bring in the code you want:
template <typename T, size_t N, int start>
struct customArray : private std::array<T,N>
{
// first, some functions to 'copy-and-paste' as-is
using std::array<T,N> :: front;
using std::array<T,N> :: begin;
// finally, the functions you wish to modify
T& operator[](const int idx) { return data_[idx+start]; }
}
The private inheritance will block conversions from customArray * to std::array *, and that's what we want.
PS: I have very little experience with private inheritance like this. So many it's not the best solution - any feedback appreciated.
General thought
The recommendation not to inherit from standard vector, is because this kind of construct is often misunderstood, and some people are tempted to make all kind of objects inherit from a vector, just for minor convenience.
But this rule should'nt become a dogma. Especially if your goal is to make a vector class, and if you know what you're doing.
Danger 1: inconsistency
If you have a very important codebase working with vectors in the range 1..size instead of 0..size-1, you could opt for keeping it according to this logic, in order not to add thousands of -1 to indexes, +1 to index displayed, and +1 for sizes.
A valid approach could be to use something like:
template <class T>
class vectorone : public vector<T> {
public:
T& operator[] (typename vector<T>::size_type n) { return vector<T>::operator[] (n-1); }
const T& operator[] (typename vector<T>::size_type n) const { return vector<T>::operator[] (n-1); }
};
But you have to remain consitent accross all the vector interface :
First, there's also a const T& operator[](). If youd don't overload it, you'll end up having wrong behaviour if you have vectors in constant objects.
Then, and it's missing above, theres's also an at() which shall be consitent with []
Then you have to take extreme care with the constructors, as there are many of them, to be sure that your arguments will not be misinterpreted.
So you have free functionality, but there's more work ahead than initially thougt. The option of creating your own object with a more limited interface, and a private vector could in the end be a safer approach.
Danger 2:more inconsistency
The vector indexes are vector<T>::size_type. Unfortunately this type is unsigned. The impact of inherit from vector, but redefine operator[] with signed integer indexes has to be carefully analysed. This can lead to subtle bugs according to the way the indexes are defined.
Conclusions:
There's perhap's more work that you think to offer a consistent std::vector interface. So in the end, having your own class using a private vector could be the safer approach.
You should also consider that your code will be maintained one day by people without fortran background, and they might have wrong assumptions about the [] in your code. Is going native c++ really out of question ?
It doesn't seem that bad to just stick with composition, and write wrappers for the member functions you need. There aren't that many. I'd even be tempted to make the array data member public so you can access it directly when needed, although some people would consider that a bigger no-no than inheriting from a base class without a virtual destructor.
template <typename T, size_t N, int start>
class customArray
{
public:
std::array<T,N> data;
T& operator[](int idx) { return data[idx+start]; }
auto begin() { return data.begin(); }
auto begin() const { return data.begin(); }
auto end() { return data.end(); }
auto end() const { return data.end(); }
auto size() const { return data.size(); }
};
int main() {
customArray<int, 7, -3> a;
a.data.fill(5); // can go through the `data` member...
for (int& i : a) // ...or the wrapper functions (begin/end).
cout << i << endl;
}
I'm trying to achieve the following: Given an abstract class MemoryObject, that every class can inherit from, I have two subclasses: A Buffer and a BigBuffer:
template <typename T>
class MemoryObject
{
public:
typedef typename std::vector<T>::iterator iterator;
typedef typename std::vector<T>::const_iterator const_iterator;
[...] //Lot of stuff
virtual iterator begin() = 0;
virtual iterator end() = 0;
};
A Buffer:
template <typename T>
class Buffer: public MemoryObject<T>
{
public:
typedef typename std::vector<T>::iterator iterator;
iterator begin() { return buffer_.begin(); }
iterator end() { return buffer_.end(); };
[...] //Lot of stuff
private:
std::vector<T> buffer_;
};
And finally:
template <typename T>
class BigBuffer: public MemoryObject<T>
{
public:
[...] //Omitted, for now
private:
std::vector<Buffer<T>*> chunks_;
};
As you can see, a BigBuffer holds a std::vector of Buffer<T>*, so you can view a BigBuffer as an aggregation of Buffer(s). Futhermore, I have a bunch of functions that must work of every MemoryObject, so this is a real signature:
template <class KernelType, typename T>
void fill(CommandQueue<KernelType>& queue, MemoryObject<T>& obj, const T& value)
{
//Do something with obj
}
What's the point? - You may ask. The point is that I must implement iterators over these classes. I've already implemented them for Buffer, and is exactly what I need: be able to iterate over a Buffer, and access to ranges (for example b.begin(), b.begin() + 50).
Obviously I can't do the same for BigBuffer, because the real data (that is inside each Buffer' private variable buffer_) is scattered accross the memory. So I need a new class, let's call it BigBufferIterator, which can overload operator like * or +, allowing me to "jump" from a memory chunk to another without incurring in in segmentation fault.
The problems are two:
The iterator type of MemoryObject is different from the iterator
type of BigBuffer: the former is a std::vector<T>::iterator, the
latter a BigBufferIterator. My compiler obviously complains
I want be able to preserve the genericity of my functions signatures
passing to them only a MemoryObject<T>&, not specializing them for
each class type.
I've tried to solve the first problem adding a template parameter classed Iterator, and giving it a default argument to each class, with a model loosely based to Alexandrescu's policy-based model. This solution solved the first issue, but not the second: my compiled still complains, telling me: "Not known conversion from BigBuffer to MemoryObject", when I try to pass a BigBuffer to a function (for example, the fill() ). This is because Iterator types are different..
I'm really sorry for this poem, but It was the only way to proper present my problem to you. I don't know why someone would even bother in reading all this stuff, but I'll take pot luck.
Thanks in advance, only just for having read till this point.
Humbly,
Alfredo
They way to go is to use the most general definition as the iterator type of the base. That is, you want to treat the data in a Buffer as just one segment while the BigBuffer is a sequence of the corresponding segments. This is a bit unfortunate because it means that you treat your iterator for the single buffer in Buffer as if it may be multiple buffers, i.e. you have a segmented structure with just one segment. However, compared to the alternative (i.e. a hierarchy of iterators with virtual functions wrapped by a handle giving value semantics to this mess) you are actually not paying to bad a cost.
I encountered the same problem in a different context; let me restate it.
You have a Base class (which could be abstract), which is iterable via its BaseIterator.
You have a Child subclass, which differs in implementation slightly, and for which you have a different specialized ChildIterator.
You have custom functions that work with Base, and rely on its iterability.
It is not feasible to generate a template specialization of the custom functions for each subclass of Base. Possible reasons may be:
huge code duplication;
you distribute this code as a library and other developers are going to subclass Base;
other classes will take some reference or pointer to Base and apply those custom functions, or more generically:
Base implements some logic that is going to be uses in contexts where do not know any of the subclasses (and writing completely templated code is too cumbersome).
Edit: Another possibility would be using type erasure. You would hide the real iterator that you're using behind a class of a fixed type. You would have to pay the cost of the virtual functions call though. Here is an implementation of a any_iterator class which implements exactly iterator type erasure, and some more background on it.
The only effective solution I could find was to write a multi-purpose iterator that can iterate over all possible containers, possibly exploiting their internals (to avoid copy-pasting the iterator code for every subclass of Base):
// A bigger unit of memory
struct Buffer;
class Iterator {
// This allows you to know which set of methods you need to call
enum {
small_chunks,
big_chunks
} const _granularity;
// Merge the data into a union to save memory
union {
// Data you need to know to iterate over ints
struct {
std::vector<int> const *v;
std::vector<int>::const_iterator it;
} _small_chunks;
// Data you need to know to iterate over buffer chunks
struct {
std::vector<Buffer *> const *v;
std::vector<Buffer *>::const_iterator it;
} _big_chunks;
};
// Every method will have to choose what to do
void increment() {
switch (_granularity) {
case small_chunks:
_small_chunks.it++;
break;
case big_chunks:
_big_chunks.it++;
break;
}
}
public:
// Cctors are almost identical, but different overloads choose
// different granularity
Iterator(std::vector<int> const &container)
: _granularity(small_chunks) // SMALL
{
_small_chunks.v = &container;
_small_chunks.it = container.begin();
}
Iterator(std::vector<Buffer *> const &container)
: _granularity(big_chunks) // BIG
{
_big_chunks.v = &container;
_big_chunks.it = container.begin();
}
// ... Implement all your methods
};
You can use the same class for both Base and Child, but you need to initialize it differently. At this point you can make begin and end virtual and return an Iterator constructed differently in each subclass:
class Base {
public:
virtual Iterator begin() const = 0;
};
class IntChild : public Base {
std::vector<int> _small_mem;
public:
virtual Iterator begin() const {
// Created with granularity 'small_chunks'
return Iterator(_small_mem);
}
// ...
};
class BufferChild : public Base {
std::vector<Buffer *> _big_mem;
public:
virtual Iterator begin() const {
// Created with granularity 'big_chunks'
return Iterator(_big_mem);
}
// ...
};
You will pay a small price in performance (because of the switch statements) and in code duplication, but you will be able to use any generic algorithm from <algorithm>, to use range-loop, to use Base only in every function, and it's not stretching the inheritance mechanism.
// Anywhere, just by knowing Base:
void count_free_chunks(Base &mem) {
// Thanks to polymorphism, this code will always work
// with the right chunk size
for (auto const &item : mem) {
// ...this works
}
// This also works:
return std::count(mem.begin(), mem.end(), 0);
}
Note that the key point here is that begin() and end() must return the same type. The only exception would be if Child's methods would shadow Base's method (which is in general not a good practice).
One possible idea would be to declare an abstract iterator, but this is not so good. You would have to use all the time a reference to the iterator. Iterator though are supposed to be carried around as lightweight types, to be assignable and easily constructible, so it would make coding a minefield.