Only allow a C++ vector to grow when resizing - c++

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

Related

How can I create a vector with a maximum length?

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.

Deciding to use at runtime a boost::static_vector or a std::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)) { }
};

Fixed size std::vector at runtime?

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.

Template constructor

The problem: I find myself faced with numerous duplicate functions to support different types of almost-identical array-like inputs. For example, a function foo might be available in the following versions:
void foo (int v); // single value, 99% of all use cases.
void foo (std::initializer_list<int> v);
void foo (const std::vector<int> &v);
void foo (int *v, int size);
This duplication bothers me. I would like to have a single function foo, that may be called with any kind of array-like data (with a single value obviously being seen as an array of size 1).
Possible solutions include:
Always use the vector version. This incurs some overhead for memory allocation on every use, and since 99% of my uses are for single values I find this undesirable.
Have an interface specifying an iterator pair. This again falls flat when attempting to call the function for a single value.
Have some sort of abstraction for array-like data that can handle all of the desired input types. This is a promising approach, but I do run into some trouble...
My implementation is called mem_range, which presents a vector-like interface (only including operations that do not change the size of the vector, obviously). The various types of arrays are supposed to be handled through different constructors of mem_range.
I have trouble specifying the constructor that is supposed to take std::array. The problem is the array size, which is part of the template definition - I cannot figure out how to create a constructor that will accept arrays of any size.
template<typename T>
class mem_range {
public:
mem_range (T *begin, T *end) { } // ok
mem_range (std::vector<T> &vec) { } // ok
template<int array_size>
mem_range<array_size> (std::array<T, array_size> &arr) { } // not ok
}
The last constructor yields "error C2988: unrecognizable template declaration/definition" on MSVC2015. I've gone through quite a few variations now, but nothing that makes the compiler happy.
Just to be clear, based on answers I've read on similar questions here on stackoverflow:
Resizing the array-like data in any way is not in scope. If I wanted that capability I'd just pass an std::vector.
I'm aware there are many questions with similar titles. None of these appear to have decent answers, usually getting no further than "why do you want this?".
I'm trying to make this work on MSVC2015 and modern GCC, so C++14/17 are fine (as far as supported).
When declaring the templated constructor, the template is understood to belong to the constructor function, so you don't need to specify it there.
You are also missing a closing bracket > after the array argument.
So the constructor should look like this:
template<int array_size>
mem_range(std::array<T, array_size>) { }
And of course, you should consider passing the array object as a reference to a constant, and using the correct type (see e.g. this std::array reference`), i.e.
template<std::size_t array_size>
mem_range(std::array<T, array_size> const&) { }
You can make array_size an optional value of the template class.
template<typename T, int array_size=0>
class mem_range {
public:
mem_range (T *begin, T *end) { } // ok
mem_range (std::vector<T> &vec) { } // ok
mem_range (std::array<T, array_size> &array) { }
}

How to add an Initializer List constructor to STL vector

So what I want to do is extend the existing vector class in my program to allow me to say this,
vector<string>* vec = new vector<string>(){"Value1","Value2"};
or
vector<string>* vec = new vector<string>({"Value1","Value2"});
or
vector<string> vec = {"Value1","Value2"};
I know I can accomplish something like this but doing this,
string temp[] = {"Value1","Value2"};
vector<string> vec(temp, temp+ sizeof(temp) / sizeof( temp[0] ) );
This uses the vectors iterator constructor but can't I remove the extra line?
I know in C# you can add whatever you want to existing things by using the partial key word like this,
public partial class ClassName
{
ClassName(Stuff stuff)
{
}
void AmazingNewMethod()
{
}
}
Does C++ have a nifty trick like this somewhere?
Do I have to inherit vector and build a customVector that has a constructor that behind the scenes does the iterator constructor thing?
Maybe wrap those lines in a static Helper Function call that sets it by Reference and add it to a toolbox class somewhere?
I feel like lots of programmers have hit this problem. Are there any elegant solutions out there?
Thanks.
Edit: fixed the title to mention this is an Initializer List constructor.
In C++11 there would be initializer lists to suite this approach. As you're mentioning .NET I now assume that you're using MS Visual Studio. Microsoft does NOT implement initializer lists, therefore the easiest way to accomplish something like that would be a function that returns the vector with all the elements added.
On the partial thing: C++ does not offer a feature in the same vein as .NET's partial classes.
The C++ 2011 way is to accept an std::initializer_list<T> as a constructor argument:
#include <initializer_list>
template <typename T>
class foo {
T *d_array;
public:
foo(std::initializer_list<T> list)
: d_array(new T[list.size()]) {
std::copy(list.begin(), list.end(), this->d_array);
}
foo(foo const&);
foo& operator= (foo const&);
~foo() { delete[] this->d_array; }
};
The above clearly only concentrates on how use an std::initializer_list<T>. To actually do the allocation internally you'd allocate raw memory and construct the object in-place. However, this wasn't what the question is about.
With respect to adding this support to std::vector<T>: you don't have to! In C++ 2011 std::vector<T> can be initialized with an std::initializer_list<T>. In C++ 2003 you can't do this. The best you could do is to support construction from an array, using a constructor looking something like this:
template <typename T>
template <typename S, int Size>
foo<T>::foo(S const (&array)[Size])
d_array(new T[Size]) {
std::copy(array, array + Size, d_array);
};
However, there is no way to extend an existing without changing its type. To avoid reimplementing most of the members you could publically inherit from the type you want to extend and add all required constructors (these are not inherited; in C++ 2011 you could inherit the existing constructors but then, with C++ 2011 you wouldn't need to do any of this anyway).
An alternative you might want to use with C++ 2003 is to create a factor function taking a built-in array, i.e. something like this:
template <typename T, typename S, int Size>
std::vector<T>
make_vector(S const (&array)[Size]) {
return std::vector<T>(array, array + Size);
}
char const* init[] = { "Hello", "World" };
std::vector<std::string> value = make_vector<std::string>(init);