Consider this poor code:
int *p = new int(42); cout << "Before: " << *p << '\n'; delete p; cout << "After: " << *p << '\n';
Before: 42 After: 5608
p
was a valid pointer, then it became
invalid.
Another way to invalidate a pointer:
string *p; { string name = "John Jacob Jingleheimer Schmidt"; p = &name; cout << p->size() << ' ' << *p << '\n'; } cout << p->size() << ' ' << *p << '\n';
vector<int> v = {253}; vector<int>::iterator it = v.begin(); cout << "Before: " << *it << '\n'; for (int i=1; i<1000; i++) v.push_back(i); cout << "After: " << *it << '\n';
Before: 253 After: 23663727
Using auto
makes the code prettier, but no better:
vector<int> v = {253}; auto it = v.begin(); cout << "Before: " << *it << '\n'; for (int i=1; i<1000; i++) v.push_back(i); cout << "After: " << *it << '\n';
Before: 253 After: 35402528
Using .reserve()
pre-allocates memory:
vector<int> v = {253}; v.reserve(1005); auto it = v.begin(); cout << "Before: " << *it << '\n'; for (int i=1; i<1000; i++) v.push_back(i); cout << "After: " << *it << '\n';
Before: 253 After: 253
How often does re-allocation happen? We can find out, for any particular implemention:
vector<int> v; cout << v.size() << ' ' << v.capacity() << '\n'; for (int i=1; i<1000; i++) { auto before = v.capacity(); v.push_back(i); auto after = v.capacity(); if (before != after) cout << v.size() << ' ' << v.capacity() << '\n'; }
0 0 1 1 2 2 3 4 5 8 9 16 17 32 33 64 65 128 129 256 257 512 513 1024
Similarly, because a std::string
is not much more
than a vector<char>
:
string s; cout << s.size() << ' ' << s.capacity() << '\n'; for (int i=1; i<10000; i++) { auto before = s.capacity(); s += 'x'; auto after = s.capacity(); if (before != after) cout << s.size() << ' ' << s.capacity() << '\n'; }
0 15 16 30 31 60 61 120 121 240 241 480 481 960 961 1920 1921 3840 3841 7680 7681 15360
vector
?
Again, if we know how many items we’re going to add, we can
.reserve()
the space:
vector<int> v; v.reserve(900); cout << v.size() << ' ' << v.capacity() << '\n'; for (int i=1; i<1000; i++) { auto before = v.capacity(); v.push_back(i); auto after = v.capacity(); if (before != after) cout << v.size() << ' ' << v.capacity() << '\n'; }
0 900 901 1800