1

I created a vector a and tried to display &a and &a[0].The addresses are very different. Isn't object address usually the same as first element address? And Isn't the object memory contiguous? And I noticed the address difference between &a+1 and &a is exactly the same size of the whole vector elements, 12 bytes in this case. It looks like a copy of the whole vector to me.

#include <iostream>
#include <vector>

using namespace std;

int main(){

    vector<int> a ={3,5,8};
    cout<<"vector object address: "<<&a<<endl;
    cout<<"vector object address +1: "<<&a+1<<endl;
    cout<<"vector data[0] address: "<<&a[0]<<endl;
    cout<<"vector data[1] address: "<<&a[1]<<endl;


    return 0;

}

Can anyone explain to me how vector object works? Below is the code output:

vector object address: 0034FEBC
vector object address +1: 0034FEC8
vector data[0] address: 007D8208
vector data[1] address: 007D820C
fuhuan26
  • 43
  • 5
  • 1
    Please take [the tour](https://stackoverflow.com/tour) and read [the help page](https://stackoverflow.com/help). Please post the code as code, not as links or images. Welcome to SO. – Ron Feb 15 '18 at 20:35
  • 2
    *"Isn't object address usually the same as first element address?"* - No, not with standard containers (except perhaps `std::array`). – Galik Feb 15 '18 at 20:36
  • To address the underlying contiguous array of `std::vector` use the [`std::vector::data()`](http://en.cppreference.com/w/cpp/container/vector/data) functions. Taking the address of the `std::vector` variable itself is a different one. [@Galik is right about that](http://coliru.stacked-crooked.com/a/2870ecca09086b7b) mentioning `std::array` as an exception. –  Feb 15 '18 at 20:41
  • The two `[]` addresses look contiguous to me. Do you remember to account for the `sizeof(int)`? – kabanus Feb 15 '18 at 20:47
  • _@fuhuan26_ It's always better to consult the [documentation](http://en.cppreference.com/w/cpp/container/vector) before asking here. `std::vector` isn't a POD replacement of the c-style `int[]` raw array. Though it's fully convertible using the `data()` functions and `size()` as mentioned. –  Feb 15 '18 at 20:52

3 Answers3

2

The explanation of what you're seeing is that std::vector doesn't follow the same rules of array decaying like a raw c-style array does:

#include <iostream>
using std::cout;
using std::endl;

int main() {

    int a[] ={3,5,8};
    cout<<"raw array object address: "<<&a<<endl;
    cout<<"raw array object address +1: "<<&a+1<<endl; // adds sizeof(a)
    cout<<"raw array data[0] address: "<<&a[0]<<endl;  // same as a + 0
    cout<<"raw array data[1] address: "<<&a[1]<<endl;  // same as a + sizeof(int)
}

Outputs:

raw array object address: 0x7ffd02ca2eb4
raw array object address +1: 0x7ffd02ca2ec0
raw array data[0] address: 0x7ffd02ca2eb4
raw array data[1] address: 0x7ffd02ca2eb8

See live demo

Can anyone explain to me how vector object works?

A std::vector instance is a non POD variable, and will have it's own address at the local storage. It merely wraps the underlying memory address that is actually used to store the data. How exactly is implementation defined, but you can consider that there's at least an interned pointer, and an allocator concept is used to obtain the memory. Keeping track of the current size, and copying to reallocated memory is managed as well.

The std::vector::data() functions are dedicated to access that guaranteed contiguous chunk of memory.

You should notice that the pointers you obtain through the mentioned data() functions aren't stable, and may get invalidated as soon the std::vector is manipulated in a way.


Also worth mentioning that std::array makes an exception here from the other standard containers:

#include <iostream>
#include <array>

using std::array;
using std::cout;
using std::endl;

int main() {

    array<int,3> a ={3,5,8};
    cout<<"std::array object address: "<<&a<<endl; // Note these addresses ...
    cout<<"std::array object address +1: "<<&a+1<<endl;
    cout<<"std::array data[0] address: "<<&a[0]<<endl; // are the same
    cout<<"std::array data[1] address: "<<&a[1]<<endl;
}

Outputs:

std::array object address: 0x7ffe72f1cf24
std::array object address +1: 0x7ffe72f1cf30
std::array data[0] address: 0x7ffe72f1cf24
std::array data[1] address: 0x7ffe72f1cf28

Live demo

1

A vector consists of two parts. One is the object itself, and it is fixed size. The other is the data contained within the vector, and it is variable. One of the members of the vector object will be a pointer to the data contained by the vector. &a returns a pointer to the vector object, and &a[0] returns a pointer to the data which is not in the same place as the object.

&a gives you the pointer to the vector object. You're using pointer arithmetic when you do &a+1, which would give you a pointer to the next vector in an array of vectors. Since you don't have an array, &a+1 is returning an invalid pointer, but C++ doesn't have any way of knowing that.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • Hi Mark, thank you for your explanation.So is that the case once the vector object a defined, `&a` value will be fixed. However, `&a[0]` value can change, if the vector expands a lot and the original address is not big enough. Am I right? You mentioned there is a member of the vector object to be the pointer to the data contained by the vector. How to invoke that pointer? That pointer's addess is always the same as `&a[0]`, right? @Mark Ransom – fuhuan26 Feb 15 '18 at 21:53
  • @fuhuan26 -- Note that `std::vector::operator [ ]` is actually a function call -- it isn't a built-in operator similar to an array. So for vector, `[ ]` can do whatever it needs to do. – PaulMcKenzie Feb 15 '18 at 21:57
  • @fuhuan26 the pointer maintained by `vector` is private, it *probably* points directly to the data but you can't be sure and it doesn't matter because you can't access it. `&a[0]` is the proper way to get a pointer to the data. And yes, it can change as the `capacity` of the vector changes - the standard guarantees it won't change otherwise. – Mark Ransom Feb 15 '18 at 22:07
  • @Mark Ransom, got you. and once vector object defined, its address `&a` will never change, even when 'capacity` changed, right? – fuhuan26 Feb 15 '18 at 22:32
  • @fuhuan26 unless that vector is part of *another* vector! But yes, the address of a local variable `a` should never change. – Mark Ransom Feb 15 '18 at 23:08
0

How the vector works is implementation defined. However they are required to store their elements dynamically on the free store by default. This means when you create a std::vector it then gets the memory for its members separately.

It could be implemented something like this:

template<typename T>
class vector
{
public:

    // The returned element will not have the same address as this
    T& operator[](std::size_t n) { return m_begin[n]; } 

private:
    T* m_begin; // start of internal array
    T* m_top;   // end of contained elements
    T* m_end;   // end of internal array
};

Note: Crucial parts missing from the above mockup

The address of the element is stored directly in the vector object, not the elements themselves.

Galik
  • 47,303
  • 4
  • 80
  • 117
  • The point is _POD type_ or not IMO. And `std::array` turned out to be exceptional as you supposed. –  Feb 15 '18 at 21:18
  • Sure, sure! I just tried a different approach of explanation (springing off from misconceptions maybe). Coming up with such confusion seems to be a bit of _natural_ (least expectation of behavior), thus this question isn't that bad. –  Feb 15 '18 at 21:20