guaranty that vector wont free memory

Hi,
I frequently write code that needs to over and over add elements to a vector and then erasing all the vector.
Usually I know in advance an upper bound to the amount of elements that may be inserted.
I then need to analyze the resulting vector, erase it and run the function again to get more results.

Example:
1
2
3
4
5
6
7
vector<int> res;
res.reserve(1000000); //an upper bound of 1 million
for (int i=0; i<10000; i++) {
   res.resize(0);
   do_stuff_and_add_elemets_to_the_vector(res);
   analyze(res);
}


My question is: Is there a guarantee that the res.resize(0) won't free the memory and then the .push_back() inside the do_stuff_and_add_elemets_to_the_vector function will allocate the memory again.
I know that on my gcc4.3 the vector doesn't get freed and I don't have unnecessarily allocations and free. But I don't know whether the ISO standard guarantees it to me.
If no, is there a clean way around it? (except tracking the number of elements myself or implementing my own vector class)

Thank you!

Comment irrelevant - removed.
Last edited on
Hi,
Look at my code. I did use the reserve function.
what I don't know is whether the res.resize(0) won't free my vector. I don't think the ISO standard actually guarantees that all implementations of the vector will not free the memory after the resize call.
I haven't done this before, but it seems to me you could guarantee it by defining a custom Allocator that will only allocate once, and never de-allocate (or assert on de-allocation). Or something along those lines.
asserting isn't a guarantee. It will just tell me if something is wrong. I want to know that it will never release the memory no matter what the future implementation of std::vector is.
The standard give this remark about vector reserve:
It is guaranteed that no reallocation takes place during insertions that happen after a call to reserve() until the time when an insertion would make the size of the vector greater than the value of capacity().
Indeed, but resize(0) never inserts any elements, so this paragraph shouldn't apply here.
Example of what I was talking about:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

template <class T>
struct my_allocator
{
	typedef T value_type;
	typedef size_t size_type;
	typedef ptrdiff_t difference_type;
	typedef T* pointer;
	typedef const T* const_pointer;
	typedef T& reference;
	typedef const T& const_reference;
	T* pAllocated = 0;
	
	my_allocator() { cout << "Constructor" << endl;}
	my_allocator(const my_allocator&) {cout << "Copy Constructor" << endl;}
	~my_allocator() {cout << "Destructor" << endl;}

	T*   allocate(size_t n, const void * = 0) 
	{
		cout << "Attempted to allocate, size = " << n << endl;
		if (!pAllocated)
		{			
			pAllocated = (T*) malloc(n * sizeof(T));
			cout << "Allocated" << endl;
			return pAllocated;
		}
		
		return pAllocated;
	}

	void deallocate(void* p, size_t) 
	{
		cout << "Attempted to de-allocate" << endl;
		return;
	}
};

int main()
{
	vector<int, my_allocator<int>> myVec(1000000);
	cout << "Pushing..." << endl;
	for (int i = 0; i < 20000; i++)
	{
		myVec[i] = i;
	}
	cout << "Done pushing" << endl;
	return 0;
}


Note: you probably want to free up the allocated block EVENTUALLY...
Last edited on
Sorry, I indeed missed the reserve call. I remove my comment.
@Athar
I guess you are right. I was thinking "the value of capacity()" was referring to the capacity right after the call to reserve but I see now that it doesn't say that.

In that case I think even push_back could reduce the capacity but no implementation would be stupid enough to do so.
push_back does not cause reduction of capacity when reserve is called first:
It is guaranteed that no reallocation takes place during insertions that happen after
a call to reserve() until the time when an insertion would make the size of the vector greater than
the value of capacity().


As for when reserve is not called:
push_back: causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid.


I'm pretty sure that what was actually meant is: "causes reallocation if and only if", which would also prohibit a reduction of capacity. However, it doesn't actually say that.
If you know in advance the approximate size of the container and you need guarantees about the allocation behavior, perhaps a regular array, possibly wrapped in a simple class, would me more appropriate.
Thanks you all for the replies.
I think this is some oversight of the standard because it should have states more precisely what the vector should do.
as for Peter87's comment:
I guess you are right. I was thinking "the value of capacity()" was referring to the capacity right after the call to reserve but I see now that it doesn't say that.

In that case I think even push_back could reduce the capacity but no implementation would be stupid enough to do so.

There is a possible scenario in which you might think is is appropriate for push_back to reduce memory.
If you never called reserve but inserted huge amount of elements then you called resize(0) and called push_back again. In that case your vector's size is only 1 but you allocated huge space for it. It might be reasonable to think that your vector should free the huge chunk it allocated and reallocate smaller space.
I know of no actual library that does so but it is a reasonable behavior and I can't be sure unless the ISO standard doesn't state it.
Athar wrote:
push_back does not cause reduction of capacity when reserve is called first
...
I'm pretty sure that what was actually meant is: "causes reallocation if and only if", which would also prohibit a reduction of capacity. However, it doesn't actually say that.

It could reduce the capacity without reallocation.

EamonKerdoll wrote:
If you never called reserve but inserted huge amount of elements then you called resize(0) and called push_back again. In that case your vector's size is only 1 but you allocated huge space for it. It might be reasonable to think that your vector should free the huge chunk it allocated and reallocate smaller space.

Yes but why not give the user a choice? In C++11 there is a shrink_to_fit function and in C++03 you can use the swap trick to reduce the capacity. In many situations the size will reach approximately the same amount as before so reducing the capacity is just a waste.
Topic archived. No new replies allowed.