c++ – Doubt about class vector

Question:

In an array the name of the array is a pointer to the array. So in iArray and &iArray[0] the same value is obtained. What I don't quite understand is what is happening when I try to repeat this with myvector .

int iArray[]={1,2,3,4};
cout<<iArray<<endl;
cout<<&iArray[0]<<endl;

std::vector<int> myvector={1,2,3,4};
cout<<myvector<<endl;

This last statement returns the following error:

 ..\YourOtherClass_test.cpp:40:9: error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'std::vector<int>')

If I treat the name, as references, that is:

cout<<&myvector<<endl;
cout<<&myvector[0]<<endl;

Print me different addresses. Working with vectors, is there any way to know where element 0 is, by the name of the vector?

Answer:

What happens is that std::vector is a class that, internally, makes use of an array, but has much more.

A raw array like the one you use in the first example has no more than the necessary memory to store the number of elements you are asking for:

                | 0x100 | 0x101 | 0x102 | 0x103 | 0x104 | 0x105 | 0x106 |0x107 |
int array[2] -> |             array[0]          |             array[1]         |

However, the std::vector class is more complex (and hence it is much more versatile than a raw array. The standard does not specify how this class should be implemented, in the case of MSVC2015 we can find a structure like this (simplifying) :

template<class _Ty, class _Ax = allocator<_Ty> >
class vector
{
  typedef typename _Ax::template rebind<_Ty>::other _Alty;
  typedef typename _Alty::pointer pointer;

  pointer _Myfirst; // pointer to beginning of array
  pointer _Mylast;  // pointer to current end of sequence
  pointer _Myend;   // pointer to end of array
  _Alty _Alval; // allocator object for values
};

Which basically tells us that, for this compiler in particular, the std::vector class manages three pointers (start of the array, end of sequence and end of the array) and an object for memory management.

std::vector uses pointers internally because, unlike a raw array, it uses dynamic memory. This explains why you can start adding elements to the vector without worrying about its size:

std::vector<int> datos;
// ...
datos.push_back(10);
datos.push_back(20);
datos.push_back(30);
// ...

While with a raw array you have to be very careful not to exceed its limits:

int array[10];
array[10] = 123; // <<--- ups!!!

It is clear that a raw array and std::vector , although they can be used with the same syntax, look like a rocket-ship bun.

Now, answering your questions …

If I treat the name, as references … It prints me different addresses

Indeed:

  • &myvector will return the memory address where the current std::vector object is located.
  • &myvector[0] returns the memory address where the first element of the vector is located. As the std::vector class makes use of dynamic memory, this memory position will hardly coincide with the one obtained in the previous point.

Working with vectors, is there any way to know where element 0 is, by the name of the vector?

And why do you want to know that information exactly?

If you need to modify only that position you can obtain it as you have done in your example:

`&myvector[0]`

But using the vector like this implies certain totally unnecessary risks:

  • If you need to modify elements of the vector, the easiest and safest way is to pass the vector as a reference:

     void func(std::vector<int> & myvector) { // ... }
  • The vector class is capable of resizing the memory that it manages in a totally automatic and transparent way for the user. If you access their memory locations as you intend and the vector is resized, you can end up accessing memory that does not belong to you.

  • To move through the vector, the most common is to use the iterators:

     std::vector<int> myvector = funcionQueGeneraUnVector(); // Hasta C++11 for( std::vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it ) { // ... } // C++11 en adelante for( auto it = std::begin(myvector); it != std::end(myvector); ++it ) { // ... }

    Iterators can be used in a thousand different ways:

     std::vector<int> datos = { 1, 4, 2, 7, 5, 9, 3, 0 }; // Localizamos la posicion del numero 7 auto it = std::find(std::begin(datos),std::end(datos),7); // Imprimimos dicho valor, despues el anterior y finalmente el posterior std::cout << *it << *(it-1) << *(it+1) << '\n'; // Eliminamos el numero 7 del vector datos.erase(it); // Imprimimos el vector sin el 7 for( int numero : datos ) std::cout << numero << ' ';

Esta última sentencia, devuelve el siguiente error:

..\YourOtherClass_test.cpp:40:9: error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'std::vector<int>')

That's because there is no insert operator overload on the ostream class that accepts an object of type std::vector . However, that is something that has a solution:

std::ostream& operator<<(std::ostream& os, std::vector<int> const& v)
{
  for( int dato : v )
    os << dato << ' ';
  return os;
}

std::vector<int> myvector={1,2,3,4};
cout<<myvector<<endl; // Imprime 1 2 3 4
Scroll to Top