C++ Fixed size container with swappable elements - c++

I'm searching for a container with the following functionality:
Fixed size at runtime. Thus, memory shouldn't be allocated in little chunks (like std::list does).
Elements should be swappable (Something like std::list::splice offers).
EDIT:
Thinking of a list: I just need to move elements from an arbitrary position to the front.
EDIT2:
I would like to use something like a std::list, but takes advantage of a runtime fixed size.

I'd think of TR1 array:
std::array<T, int>
Or, if you haven't got that yet,
boost::array<T, int>
Which is identical for all intents and purposes. Of course the validity of std::swap on elements depends on availability of proper copy constructor/assignment operator.

It's not too clear to me what you are looking for. Two solutions come to mind: std::vector (created with the maximum size), coupled with a good implementation of swap for your objects, or a custom allocator for std::list, which pre-allocates the number of nodes you'll need in a single block.

You can specify the (initial) size of an std::list at construction time :
std::list<Type> myList = std::list<Type>(10);
You can still grow/shrink it afterwards, but the list will contain 10 default constructed Type objects from the start.
Does that suit your needs ?

std::vector ?
Array based. Can specify the size and has a swap function.
You haven't said what you'll be using it for so I don't really know if you're going to have any speed issues with it.

Related

container class for constant data with compile time initialization

I search something which is std::vector but without the big overhead and a bit more than std::array, because with std::array I did not have the size stored anyway ( it is only known from the type itself ).
What I want to achieve:
Written with "dynamic" containers it is like:
std::map< int, std::vector< std::pair<int,int>>>;
I need no modification during runtime, but I need the size information during runtime. Replacing std::vector with std::array could not work, because the array must be the same size for all map entries which is not what I need.
I only! want to ask if there is already an available implementation around. If the answer is simply "No", there is no need for a suggestion how to do the job. I only want to not reinvent the wheel again :-)
Background: I can use the stl on my small avr controllers, but the overhead is "a bit" to high. So I search for a hopefully standard implementation which fit the needs for compile time constant representation with implemented features like begin()/end() and iterators to fulfill the minimum container requirements to get them used with range based for and others.
c++14 is also available, if there is something I search for.
All what I found is full template implemented where the access to the data is also compile time constant like:
container.get<2>()
which I also could not use, because I need runtime vars to access my data.
EDIT: Which problem/overhead comes up while using std::vector:
While using std::vector I need also new/delete which results in having malloc/free for avr. I also found that on avr the initialization of the vector itself takes arround 350 bytes code for each template instance I use. The access functions like operator[] and also the iterators are very small.
To avoid the overhead of std::vector, you may use instead std::initializer_list
const std::map<int, std::initializer_list<std::pair<int, int>>>
Not entirely clear to me what you're looking for, but I think you could achieve what you need with the following:
You don't know the exact size of each contained element (say N elements), and you will know it when program starts. Then, whenever you know the size of the containers, reserve just one contiguous memory block to hold all the inner elements of all the containers. (one dynamic allocation)
Create the map with vectors constructed via range: std::vector(start, end), where start and end are calculated via blocks of N elements.
Then populate the map. If you don't strictly need a map, you can also calculate where each vector will begin and end, and just create an initial array with indexes of the positions of each vector...
What you are asking seems to be impossible in principle. You say you want to avoid heap allocation of your vector like type, but the size of a type on the stack must be known at compile time, and the same for all members of that type. Since map is a homogeneous container, the value type must be a single type with a constant size. You could replace the map with a tuple, but then all of your keys would have to be known at compile time.

Unordered, fixed-size memory-pool based container with frequent insertion and deletion

I'm looking for a container to store a dynamically growing and shrinking family of objects the size of which I know to come near to but never exceed a given bound. The container need not be ordered, so that I'm happy with any kind of insertion, no matter where it takes place. Moreover, I want all the objects to be stored in a some fixed contiguous memory-pool, but I do not require the memory that is actually occupied at some point in time to be a connected interval in the memory-pool.
Is there any container/allocator in the STL or boost that provides the above?
It seems that a reasonable approach would be to use a linked list with memory taken from a fixed-size memory-pool, but I'd rather use some already existing and well-established implementation for this than trying to do it myself.
Thank you!
As you need elements to be contiguous, I think you should go for std::vector, calling reserve at the beginning.
As I said in comment, as soon as you need contiguous memory you'll have to move something when you delete in the middle and that behavior is already handled by std::vectorusing remove/erase idiom.
Apart from this, if you use only the vector insertion or the lookup will be costly according to your design:
Either you always add new element at the end and the lookup of an element will cost you but the insertion will be painless
Or you sort the vector after every insertion (that will cost) and your lookup will be a lot faster using std::equal_range
Otherwise if you can afford an additional std::unordered_set<std::vector<your_element>::iterator> with a custom hash/equal you have a fair insertion/lookup ratio by looking up with the std::unordered_set<> to find where your element is stored.
Recapping, your requirements are:
dynamically growing and shrinking
no need to be ordered
fixed contiguous memory-pool
With the third requirement you rule out most of the node based containers (such as lists or queues). What you are left with are array-like containers. Specifically std::array and std::vector (or even std::valarray/boost::valarray).
But with the first requirement you rule out std::array (unless you want to implement some weird looking std::array<std::optional<T>> that mimics the functionality of an std::vector).
What you are left with is std::vector, which happens to fit requirement number two as well. Of course you can manage the capacity with std::vector::reserve and std::vector::shrink_to_fit.

Standard containers that reserve on construction?

I want a standard C++ container to use as an accumulator for reading from a network socket (that is, T = byte or unsigned char). I want the container to reserve a capacity on construction, and not initialize the elements. That is, I want to be able to do:
container c(1024);
and get the container to reserve 1024 octets. One-step construction/capacity is important because I want to use it in an initializer.
I also want contiguous storage. If the containers must grow, the new storage should be contiguous.
I also want to be able to append bytes to the container. And I want to be able to search for byte strings in the container.
vector and string don't really fit because construction and reserve are two step process, they use an extra allocation, and they initialize elements. Plus, vector is missing the search functionality. (EDIT: vector is fine thanks to <algorithm>; thanks DYP and Lightness Races in Orbit).
Are there any C++ standard containers that have the properties?
You are asking the wrong question.
The Standard Library does not provide a container for each and every use, instead it provides a selection of useful building bricks.
If you want contiguous storage, then you should be using std::vector and look into making it match your other requirements:
non-initialization is accomplished by providing an allocator with a no-op construct method
and searching for a pattern is accomplished by using std::search or rolling your own specific search algorithm (Knuth Morris Pratt, Boyer Moore, ...)
In any case, I advise encapsulating the vector into a dedicated class with a clear semantic role.

how c++ vector works

Lets say if I have a vector V, which has 10 elements.
If I erase the first element (at index 0) using v.erase(v.begin()) then how STL vector handle this?
Does it create another new vector and copy elements from the old vector to the new vector and deallocate the old one? Or Does it copy each element starting from index 1 and copy the element to index-1 ?
If I need to have a vector of size 100,000 at once and later I don't use that much space, lets say I only need a vector of size 10 then does it automatically reduce the size? ( I don't think so)
I looked online and there are only APIs and tutorials how to use STL library.
Is there any good references that I can have an idea of the implementation or complexity of STL library?
Actually, the implementation of vector is visible, since it's a template, so you can look into that for details:
iterator erase(const_iterator _Where)
{ // erase element at where
if (_Where._Mycont != this
|| _Where._Myptr < _Myfirst || _Mylast <= _Where._Myptr)
_DEBUG_ERROR("vector erase iterator outside range");
_STDEXT unchecked_copy(_Where._Myptr + 1, _Mylast, _Where._Myptr);
_Destroy(_Mylast - 1, _Mylast);
_Orphan_range(_Where._Myptr, _Mylast);
--_Mylast;
return (iterator(_Where._Myptr, this));
}
Basically, the line
unchecked_copy(_Where._Myptr + 1, _Mylast, _Where._Myptr);
does exactly what you thought - copies the following elements over (or moves them in C++11 as bames53 pointed out).
To answer your second question, no, the capacity cannot decrease on its own.
The complexities of the algorithms in std can be found at http://www.cplusplus.com/reference/stl/ and the implementation, as previously stated, is visible.
Does it copy each element starting from index 1 and copy the element to index-1 ?
Yes (though it actually moves them since C++11).
does it automatically reduce the size?
No, reducing the size would typically invalidate iterators to existing elements, and that's only allowed on certain function calls.
I looked online and there are only APIs and tutorials how to use STL library. Is there any good references that I can have an idea of the implementation or complexity of STL library?
You can read the C++ specification which will tell you exactly what's allowed and what isn't in terms of implementation. You can also go look at your actual implementation.
Vector will copy (move in C++11) the elements to the beginning, that's why you should use deque if you would like to insert and erase from the beginning of a collection. If you want to truly resize the vector's internal buffer you can do this:
vector<Type>(v).swap(v);
This will hopefully make a temporary vector with the correct size, then swaps it's internal buffer with the old one, then the temporary one goes out of scope and the large buffer gets deallocated with it.
As others noted, you may use vector::shrink_to_fit() in C++11.
That's one of my (many) objection to C++. Everybody says "use the standard libraries" ... but even when you have the STL source (which is freely available from many different places. Including, in this case, the header file itself!) ... it's basically an incomprehensible nightmare to dig in to and try to understand.
The (C-only) Linux kernel is a paragon of simplicity and clarity in contrast.
But we digress :)
Here's the 10,000-foot answer to your question:
http://www.cplusplus.com/reference/stl/vector/
Vector containers are implemented as dynamic arrays; Just as regular
arrays, vector containers have their elements stored in contiguous
storage locations, which means that their elements can be accessed not
only using iterators but also using offsets on regular pointers to
elements.
But unlike regular arrays, storage in vectors is handled
automatically, allowing it to be expanded and contracted as needed.
Vectors are good at:
Accessing individual elements by their position index (constant time).
Iterating over the elements in any order (linear time).
Add and remove elements from its end (constant amortized time).
Compared to arrays, they provide almost the same performance for these
tasks, plus they have the ability to be easily resized. Although, they
usually consume more memory than arrays when their capacity is handled
automatically (this is in order to accommodate extra storage space for
future growth).
Compared to the other base standard sequence containers (deques and
lists), vectors are generally the most efficient in time for accessing
elements and to add or remove elements from the end of the sequence.
For operations that involve inserting or removing elements at
positions other than the end, they perform worse than deques and
lists, and have less consistent iterators and references than lists.
...
Reallocations may be a costly operation in terms of performance, since
they generally involve the entire storage space used by the vector to
be copied to a new location. You can use member function
vector::reserve to indicate beforehand a capacity for the vector. This
can help optimize storage space and reduce the number of reallocations
when many enlargements are planned.
...
I only need a vector of size 10 then does it automatically reduce the size?
No it doesn't automatically shrink.
Traditionally you swap the vector with a new empty one: reduce the capacity of an stl vector
But C++x11 includes a std::vector::shrink_to_fit() which it does it directly

Sharing an array with STL vectors

I would like to share the contents of an array of doubles a of size k with one or more STL vectors v1, v2...vn.
The effect that I want from this shared storage is that if the underlying array gets modified the change can be observed from all the vectors that share its contents with the array.
I can do that by defining the vectors v1...vn as vectors of pointers
vector<double*> v1;
and copy the pointers a to a + k into this vector. However, I do not like that solution. I want the vectors to be a vector of doubles.
Given that you can extract the underlying pointer from a vector I am assuming one could initialize a vector with an array in such a way that the contents are shared. Would appreciate help about how to do this.
Given that you can extract the underlying pointer from a vector I am assuming one could initialize a vector with an array in such a way that the contents are shared.
No, you can't do this. The Standard Library containers always manage their own memory.
Your best option is to create the std::vector<double> and then use it as an array where you need to do so (via &v[0], assuming the vector is non-empty).
If you just want to have the container interface, consider using std::array (or boost::array or std::tr1::array) or writing your own container interface to encapsulate the array.
This sounds to me like you want to alias the array with a vector. So logically you want a vector of references (which doesn't work for syntactical reasons). If you really really need this feature, you can write your own ref wrapper class, that behaves exactly like an actual C++ reference, so the users of your vn vectors wont be able to distinguish between vector<T> and vector<ref<T> > (e.g. with T = double). But internally, you could link the items in the vectors to the items in your "master" array.
But you should have darned good reasons to do this overhead circus :)
OK, Standard Library containers are both holders of information, and enumerators for those elements. That is, roughly any container can be used in almost any algorithm, and at least, you can go through them using begin() and end().
When you separate both (element holding and element enumeration), as in your case, you may consider boost.range. boost.range gives you a pair of iterators that delimit the extent to which algorithms will be applied, and you have the actual memory store in your array. This works mostly to read-access them, because normally, modifying the structure of the vector will invalidate the iterators. You can recreate them, though.
To answer your question, as far as I know std::vector can not be given an already constructed array to use. I can not even think how that could be done since there are also the size/capacity related variables. You can possibly try to hack a way to do it using a custom allocator but I feel it will be ugly, error prone and not intuitive for future maintenance.
That said, if I may rephrase your words a bit, you are asking for multiple references to the same std::vector. I would either do just that or maybe consider using a shared_ptr to a vector.