Vectors: Can you use reserve for a string vector?

The program crashes when I use reserve:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <vector>

using namespace std;

int main()
{
	vector<string> v;

	v.reserve(v.size() + 1);
	v[v.size() - 1] = "test"; //Crash

	cout << v[v.size() - 1] << endl;

    return 0;
}


But when I use resize, it works out fine:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <vector>

using namespace std;

int main()
{
	vector<string> v;

	v.resize(v.size() + 1);
	v[v.size() - 1] = "test";

	cout << v[v.size() - 1] << endl;

    return 0;
}



test


Resize is more inefficient than reserve since it initialises the new space for me when it's already going to be initialised by me with "test" anyway. Am I forced to use resize?
Remember that the vector size is zero when you use vector::reserve. And vector::reserve does not change the size of vector, just capacity.

You are accessing an out-of-bounds, garbage element that is not yet initialized. That is what we call 'undefined behavior'.
So resize is my only option and is efficient?
No.
1
2
3
4
5
6
7
8
9
10
11
12
vector<int> foo; // this is an empty vector
assert( foo.size() == 0 ); // There is no foo[0]

// Magic

foo.push_back( 42 ); // Now the vector has one element
assert( foo.size() == 1 ); // There is foo[0] and it has 42

// print all elements:
for ( auto e : foo ) {
  cout << e << '\n';
}


The vector has both capacity and size. size <= capacity.

1. If size < capacity and you do push_back, then the size simply increases by one and the new value is stored.

2. If size == capacity and you do push_back, then first the capacity is increased and after that the case 1 applies.


The resize() changes size. If that requires increse of capacity, that is done too.

The reserve() changes capacity, but does not change the size.

If we had in the 'Magic' above a foo.reserve( N );, then we could do N push_backs before size==capacity.


There are two ways to access an element in the vector:
1
2
foo[i]
foo.at(i)

The at() should give a better error, when you use invalid index.
should i stick to foo[i]?
No, you should stick to foo.at(i), since it does bounds checking and will raise an exception in case i is out of range. If you don't handle that error, your program will crash, which is far better than invoking undefined behavior and doing who knows what.

You're falling victim to "premature optimization". Don't worry about "efficiency" until you need to. CPU time is cheap; yours is not. Savings on the order of cycles -- "micro-optimizations" -- are never worth your time unless you're in a very uncommon situation.

std::vector offers amortized constant time insertion at the end, so it will almost always be sufficiently fast while doing that. Wait until it isn't to run the performance profiler and speed up only the slow code.

And if your program doesn't turn out fast enough, remember that the vast majority of program time will be spent in the same slow region or regions of a program. Use a performance profiler to find those regions and optimize only those regions, until your code is quick enough. You should always focus on algorithmic complexity before trying to shave off extra cycles by trying to change the capacity of a vector of strings.

P.S.: micro optimizations are a waste of time to implement, but free ones aren't. Never write std::vector::push_back() again. Replace it with emplace_back() because it's sometimes faster (if you use it right), never slower.
Last edited on
http://stackoverflow.com/a/6911339/3881189
It says that I should use [] when the program will never go out of bounds, and that there shouldn't really be a case of .at() being in release code. What are your thoughts of that?

I tried out the error codes:
.at() returned 3 where as [] returned -1073741819
Topic archived. No new replies allowed.