How do I reserve space for std::vector/std::string? - c++

I'm looking for a way that prevents std::vectors/std::strings from growing in a given range of sizes (say I want to assume that a string will hold around 64 characters, but it can grow if needed). What's the best way to achieve this?

Look at the .reserve() member function. The standard docs at the SGI site say
[4] Reserve() causes a reallocation manually. The main reason for
using reserve() is efficiency: if you know the capacity to which your
vector must eventually grow, then it is usually more efficient to
allocate that memory all at once rather than relying on the automatic
reallocation scheme. The other reason for using reserve() is so that
you can control the invalidation of iterators. [5]
[5] A vector's iterators are invalidated when its memory is
reallocated. Additionally, inserting or deleting an element in the
middle of a vector invalidates all iterators that point to elements
following the insertion or deletion point. It follows that you can
prevent a vector's iterators from being invalidated if you use
reserve() to preallocate as much memory as the vector will ever use,
and if all insertions and deletions are at the vector's end.
That said, as a general rule unless you really know what is going to happen, it may be best to let the STL container deal with the allocation itself.

You reserve space for vector and string by their reserve(size_type capacity) member function. But it doesn't prevent it from anything :). You're just telling it to allocate at least that much of uninitialized memory (that is, no constructors of your type will be called) and resize to more if needed.
std::vector<MyClass> v;
v.reserve(100); //no constructor of MyClass is called
for(int i = 0; i < 100; ++i)
{
v.push_back(MyClass()); // no reallocation will happen. There is enough space in the vector
}

For vector:
std::vector<char> v;
v.reserve(64);
For string:
std::string s;
s.reserve(64);
Where's your C++ Standard Library reference got to?

Both of them have member function called reserve which you can use to reserve space.
c.reserve(100); //where c is vector (or string)

Related

Use a ::std::vector for array creation

I want to grow a ::std::vector at runtime, like that:
::std::vector<int> i;
i.push_back(100);
i.push_back(10);
At some point, the vector is finished, and i do not need the extra functionality ::std::vector provides any more, so I want to convert it to a C-Array:
int* v = i.data();
Because I will do that more than once, I want to deallocate all the heap memory ::std::vector reserved, but I want to keep the data, like that (pseudo-code):
free(/*everything from ::std::vector but the list*/);
Can anybody give me a few pointers on that?
Thanks in advance,
Jack
In all the implementations I have seen, the allocated part of a vector is... the array itself. If you know that it will no longer grow, you can try to shrink it, to release possibly unused memory:
i.shrink_to_fit();
int* v = i.data();
Of course, nothing guarantees that the implementation will do anything, but the only foolproof alternative would be to allocated a new array, move data from the vector to the array and clear the vector.
int *v = new int[i.size];
memcpy(v, i.data, i.size * sizeof(int));
i.clear();
But I really doubt that you will have a major gain that way...
You can use the contents of a std::vector as a C array without the need to copy or release anything. Just make sure that std::vector outlives the need for your pointer to be valid (and that further modifications which could trigger a reallocation are done on the vector itself).
When you obtain a pointer to internal storage through data() you're not actually allocating anything, just referring to the already allocated memory.
The only additional precaution you could use to save memory is to use shrink_to_fit() to release any excess memory used as spare capacity (though it's not guaranteed).
You have two options:
Keep data in vector, but call shrink_to_fit. All overhead you'll have - is an extra pointer (to the vector end). It is available since C++ 11
Copy data to an external array and destroy the vector object:
Here is the example:
std::vector<int> vec;
// fill vector
std::unique_ptr<int[]> arr(new int[vec.size()]);
std::copy(vec.begin(), vec.end(), arr.get());

std::vector::assign - reallocates the data?

I am working with STL library and my goal is to minimize the data reallocation cases.
I was wndering, does
std::vector::assign(size_type n, const value_type& val)
reallocated the data if the size is not changed or does is actually just assign the new values (for example, using operator=) ?
The STL documentation at http://www.cplusplus.com/ sais the following (C++98):
In the fill version (2), the new contents are n elements, each initialized to a copy of val.
If a reallocation happens,the storage needed is allocated using the internal allocator.
Any elements held in the container before the call are destroyed and replaced by newly constructed elements (no assignments of elements take place).
This causes an automatic reallocation of the allocated storage space if -and only if- the new vector size surpasses the current vector capacity.
The phrase "no assignments of elements take place" make it all a little confusing.
So for example, I want to have a vector of classes (for example, cv::Vec3i of OpenCV). Does this mean, that
the destructor or constructor of cv::Vec3i will be called?
a direct copy of Vec3i memory will be made and fills the vector?
what happens, if my class allocates memory at run time with new
operator? This memory cannot be accounted for by plain memory
copying. Does it mean, that assign() should not be used for such
objects?
EDIT: the whole purpose of using assign in this case is to set all values in the vector to 0 (in case I have std::vector< cv::Vec3i > v). It will be done many-many times. The size of std::vector itself will not be changed.
what i want to do (in a shorter way) is the following:
for(int i=0; i<v.size(); i++)
for(int j=0; j<3; j++)
v[i][j] = 0;
right now I am interested in C++98
std::vector.assign(...) does not reallocate the vector if it does not have to grow it. Still, it must copy the actual element.
If you want to know what the standard guarantees, look in the standard: C++11 standard plus minor editorial changes.
I assume that you have a vector filled with some data and you call an assign on it, this will:
destroy all the elements of the vector (their destructor is called) like a call to clear()
fill the now-empty vector with n copies of the given object, which must have a copy constructor.
So if your class allocates some memory you have to:
take care of this in your copy constructor
free it in the destructor
Reallocations happen when the size exceed the allocated memory (vector capacity). You can prevent this with a call to reserve(). However I think that assign() is smart enough to allocate all the memory it needs (if this is more than the already allocated) before starting to fill the vector and after having cleared it.
You may want to avoid reallocations because of their cost, but if you are trying to avoid them because your objects cannot handle properly, then I strongly discourage you to put them in a vector.
The semantics of assign are defined the standard in a quite straightforward way:
void assign(size_type n, const T& t);
Effects:
erase(begin(), end());
insert(begin(), n, t);
This means that first the destructors of the elements will be called. The copies of t are made in what is now a raw storage left after the lifetime of the elements ended.
The requirements are that value_type is MoveAssignable (for when erase doesn't erase to the end of the container and needs to move elements towards the beginning).
insert overload used here requires that value_type is CopyInsertable and CopyAssignable.
In any case, vector is oblivious to how your class is managing its own resources. That's on you to take care of. See The Rule of Three.
As in the case of vector::resize method,
std::vector::assign(size_type n, const value_type& val)
will initialize each element to a copy of "val". I prefer to use resize as it minimizes the number of object instanciations/destructions, but it does the same. Use resize if you want to minimize the data realloc, but keep in mind the following:
While doing this is safe for certain data structures, be aware that assigning /pushing elements of a class containing pointers to dynamically allocated data (e.g. with a new in the constructor) may cause havoc.
If your class dynamically allocates data then you should reimplement the YourClass::operator= to copy the data to the new object instead of copying the pointer.
Hope that it helps!

Remove elements (and change size) of std::vector without affecting allocated memory

I'm using code such as the following:
const int MY_SIZE = 100000;
std::vector<double> v;
v.reserve(MY_SIZE);
// add no more than MY_SIZE elements to the vector
f(v);
v.clear();
// again, add no more than MY_SIZE elements to the vector
f(v);
v.clear();
//
// etc...
//
The point of my code is to store MY_SIZE double's and then perform an operation f(std::vector<double>) on those elements. After I fill up the vector and perform the operation, I want to get rid of all the elements (and reset std::vector::size() to 0), and then add more elements. But, the key here is that I do not want to cause the space in memory allocated for the vector to be changed.
Note than I'm never going to add more than MY_SIZE elements to v, so v should never need to reallocate more memory than was allocated by v.reserve(MY_SIZE).
So, when I call v.clear() in the above code, will it affect in any way the amount of space allocated by v.reserve(MY_SIZE) or the location in memory of v.begin()?
Related question: If I call v.erase(v.begin(),v.begin()+v.size()), will it affect in any way the amount of space allocated by v.reserve(MY_SIZE) or the location in memory of v.begin()?
If I really just wanted to erase all the elements, I would call clear(). But I'm wondering about this related question because there are occasions when I need to erase only the first X elements of v, and on these occasions I want to keep the memory allocated by v.reserve(MY_SIZE) and I don't want the location of v to change.
It seems the C++ standard (2003) implicitly guarantees that the memory is not reallocated if you call the clear() or erase() method of the std::vector.
According to the requirements of the Sequence (table 67) the a.clear() is equivalent to a.erase(begin(),end()).
Furthermore, the standard states that the erase(...) member function of the std::vector<T> does not throw an exception unless one is thrown by the copy constructor of T (section 23.2.4.3). Hence it is implicitly guaranteed, because a reallocation could cause an exception (sections 3.7.3, 20.4.1.1).
Also v.begin() remains the same, as erase(...) will only invalidate all iterators after the point of the erase (section 23.2.4.3). However, it won't be dereferenceable (since v.begin() == v.end()).
So, if you have a standard compliant implementation you are fine...
CORRECTION
My reasoning is flawed. I managed to show that erase(...) does not reallocate, but an implementation could still deallocate the memory if you erase all elements. However, if a.capacity() reports "you can add N elements without reallocating memory" after the erase/clear you are fine.
The C++11 standard defines a.clear() without referring to a.erase(...). a.clear() is not allowed to throw an exception. Hence it could deallocate, but not reallocate. So you should check the capacity after clearing the vector to make sure that the memory is still there and the next resize won't reallocate.

Reallocation in std::vector after std::vector.reserve()

I have a snippet of code where I first put some values in to a std::vector and then give an address of each of them to one of the objects that will be using them, like this:
std::vector < useSomeObject > uso;
// uso is filled
std::vector < someObject > obj;
for (int i=0; i < numberOfDesiredObjects; ++i){
obj.push_back(someObject());
obj.back().fillWithData();
}
for (int i=0; i < numberOfDesiredObjects; ++i){
uso[i].setSomeObject(&obj[i]);
}
// use objects via uso vector
// deallocate everything
Now, since I'm sometimes a little bit of a style freak, I think this is ugly and would like to use only 1 for loop, kind of like this:
for (int i=0; i < numberOfDesiredObjects; ++i){
obj.push_back(someObject());
obj.back().fillWithData();
uso[i].setSomeObject(&obj.back());
}
Of course, I can not do that because reallocation happens occasionally, and all the pointers I set became invalid.
So, my question is:
I know that std::vector.reserve() is the way to go if you know how much you will need and want to allocate the memory in advance. If I make sure that I am trying to allocate enough memory in advance with reserve(), does that guarantee that my pointers will stay valid?
Thank you.
Sidenote. This is a similar question, but there is not an answer to what I would like to know. Just to prevent it from popping up as a first comment to this question.
This is, in fact, one of the principal reasons for using reserve. You
are guaranteed that appending to the end of an std::vector will not
invalidate iterators, references or pointers to elements in the vector
as long as the new size of the vector does not exceed the old capacity.
If I make sure that I am trying to allocate enough memory in advance with reserve(), does that guarantee that my pointers will stay valid?
Yes, it guarantees your pointers will stay valid unless:
The size increases beyond the current capacity or
Unless, you erase any elements, which you don't.
The iterator Invalidation rules for an vector are specified in 23.2.4.3/1 & 23.2.4.3/3 as:
All iterators and references before the point of insertion are unaffected, unless the new container size is greater than the previous capacity (in which case all iterators and references are invalidated)
Every iterator and reference after the point of erase is invalidated.

Is the following std::vector code valid?

std::vector<Foo> vec;
Foo foo(...);
assert(vec.size() == 0);
vec.reserve(100); // I've reserved 100 elems
vec[50] = foo; // but I haven't initialized any of them
// so am I assigning into uninitialized memory?
Is the above code safe?
It's not valid. The vector has no elements, so you cannot access any element of them. You just reserved space for 100 elements (which means that it's guaranteed that no reallocation happens until over 100 elements have been inserted).
The fact is that you cannot resize the vector without also initializing the elements (even if just default initializing).
You should use vec.resize(100) if you want to index-in right away.
vec[50] is only safe if 50 < vec.size(). reserve() doesn't change the size of a vector, but resize() does and constructs the contained type.
It won't work. While the container has 100 elements reserved, it still has 0 elements.
You need to insert elements in order to access that portion of memory. Like Jon-Eric said, resize() is the way to go.
std::vector::reserve(100) will claim 100*sizeof(Foo) of free memory, so that further insertion to a vector will not do a memory allocation until 100*sizeof(foo) is full, but accessing the element of that vector will give indeterministic content of that element, since its only claim the memory not allocate it.
Before you can use operator[] to access 50th element you should either call resize, push_back() something 50 times or use std::fill_n algorithm.