DarioP
DarioP

Reputation: 5465

Different addresses while filling a std::vector

Wouldn't you expect the addresses printed by the two loops to be the same? I was, and I cannot understand why (sometimes) they are different.

#include <iostream>
#include <vector>
using namespace std;

struct S {
  void print_address() {
    cout << this << endl;
  }
};

int main(int argc,char *argv[]) {
  vector<S> v;
  for (size_t i = 0; i < 10; i++) {
    v.push_back( S() );
    v.back().print_address();
  }
  cout << endl;
  for (size_t i = 0; i < v.size(); i++) {
    v[i].print_address();
  } 
  return 0;
}

I tested this code with many local and on-line compilers and the output I get looks like this (the last three figures are always the same):

0xaec010
0xaec031
0xaec012
0xaec013
0xaec034
0xaec035
0xaec036
0xaec037
0xaec018
0xaec019

0xaec010
0xaec011
0xaec012
0xaec013
0xaec014
0xaec015
0xaec016
0xaec017
0xaec018
0xaec019

I spotted this because making some initialization in the first loop I obtained uninitialized object in the subsequent part of the program. Am I missing something?

Upvotes: 1

Views: 108

Answers (4)

juanchopanza
juanchopanza

Reputation: 227468

The vector is performing re-allocations in order to grow as needed. Each time it does this, it allocates a larger buffer for the data and copies the elements across. You can see this clearly in the first loop, where each address jump is followed by a larger sequence of consecutive addresses. In the second loop, you just look at the addresses after the final reallocation.

0xaec010
0xaec031  <--
0xaec012  <--
0xaec013
0xaec034  <--
0xaec035
0xaec036
0xaec037
0xaec018  <--
0xaec019

The simplest way to instantiate a vector with 10 S objects would be

std::vector<S> v(10);

This would involve no re-allocations. See also std::vector::reserve.

Upvotes: 2

billz
billz

Reputation: 45420

Because when vector capicity changes, it reallocates elements. If you std::vector::reserve enough capacity, no reallcation is needed, it will print same address.

vector<S> v;
v.reserve(10);

Note: properly use std::vector::reserve will increase application performance, because no unnecessary reallocation and objects copy.

Upvotes: 4

Tom Tanner
Tom Tanner

Reputation: 9354

I'm not really surprised that they can change. As the vector initially has no size, it's likely to reallocate the vector once or twice during the initial loop. That'll change the base address of the vector. It's not impossible that after a resize, you'll end up using an address you used before (though I find that somewhat surprising. Are you sure about the first part of the addresses?)

If you want to ensure they don't change, you need to add a v.reserve() before you start pushing stuff on it.

Upvotes: 0

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385244

Vector elements are stored contiguously; that is, they're all in a row in memory. Your vector object has to allocate space for this contiguous block of elements.

Your vector can't just keep having things added to it indefinitely. It has to grow the space it has allocated. The memory model typically doesn't allow us to expand a memory block — we have to create a new one instead. When the vector does this, it has to move all its elements to the new space. This is occurring several times within your first loop.

If you'd done:

vector<S> v;
v.reserve(10);

(which you can, since you know you'll end up with 10 elements), then no re-allocation would have been necessary, and the addresses would not have changed.

Upvotes: 1

Related Questions