Doubt about the class vector

5

In an array the name of the array is a pointer to the array. So in iArray and &iArray[0] you get the same value. What I do not understand very well, is that it is happening when I try to repeat this same 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 try the name, as references.It is:

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

I print different addresses. Working with vectors, is there any way of knowing where element 0 is, by the name of the vector?

    
asked by Jcpardo 10.05.2018 в 00:58
source

2 answers

3

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

A raw array like the one you use in the first example has only the memory needed to store the number of elments you are asking for:

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

However, the class std::vector 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 one ( 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
};

That basically comes to say that, for this particular compiler, the class std::vector 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 churro to a space rocket.

Now, answering your questions ...

  

If I try the name, as references ... I print different addresses

Indeed:

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

Working with vectors, is there any way of knowing 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 get it as you have done in your example:

'&myvector[0]'

But using the vector in this way 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 class vector is able to resize the memory it manages in a fully 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 around 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 << ' ';
    
  

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>')

That's because does not exist an overload of the insertion operator on the class ostream 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
    
answered by 10.05.2018 / 08:12
source
3

I love chocolate, but I do not understand why I can not eat it without unwrapping it!

The same thing happens to you with std::vector .

The class std::vector is a wrapper over a dynamic memory space, but it is not that memory space and therefore will not act as if it were.

When you execute this code:

int iArray[] = {1, 2, 3, 4};
std::cout << iArray << '\n';

It will not show you 1 if not a memory address that (as you have indicated) will match &iArray[0] . Instead this code ...

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

... is asking to spend% wrapper%, not the memory that the wrapper is managing. You can get the effect of "passing the memory address of the first element" like this:

std::vector<int> myvector = {1, 2, 3, 4};
std::cout << myvector.data() << '\n';

The std::cout function returns the pointer to the memory handled by the std::vector::data . You will get the same effect like this:

std::vector<int> myvector = {1, 2, 3, 4};
std::cout << &myvector[0] << '\n';

Since std::vector offers a indexing operator that returns a reference to the element whose index you pass in the brackets, and request the address memory of a reference is how to request it from the referenced object. But if you want to do exactly the same as with a 1 training, you must create an injection operator in data flow ( std::vector ) on << :

template <typename T>
std::ostream operator <<(std::ostream &out, const std::vector<T> &v)
{
    return (out << v.data());
}

int main()
{
    int iArray[] = {1, 2, 3, 4};
    std::cout << iArray << '\n';
    std::cout << &iArray[0] << '\n';

    std::vector<int> myvector = {1, 2, 3, 4};
    // Correcto, llama al operador que creamos antes
    std::cout << myvector << '\n';
    std::cout << &myvector[0] << '\n';

    return 0;
}
  • Also known as array, or in English array.
  • answered by 10.05.2018 в 09:47