0

I'm new in c++ programming;in my program i have to allocate dynamically one vector of vectors and two vectors with std::vector after read it from .csv file.If the matrix can't be allocate in the heap i have to use different functions .But i have no idea about how this behaves from an allocating point of view.

Federico
  • 35
  • 1
  • 8
  • sorry but i searched a lot but about this problem i find nothing.Because i don't know how a vector cell from std::vector is stored and how much memory it occupies – Federico Dec 19 '15 at 14:45
  • 1
    @Federico vector will occupy the same amount of dynamic memory as an array of the same size. – molbdnilo Dec 19 '15 at 14:49
  • A vector will use a fixed trivial amount more memory than a dynamic C array of the same objects. That trivial extra can be ignored in big vectors. If you have a very large number of tiny vectors, that trivial extra might be worth worrying about. Also, a vector built up incrementally (such as using `push_back`) occupies much more space than it would have, if you had known the final size in advance `and done a `reserve` first. – JSF Dec 19 '15 at 15:22
  • I left a thorough explanation of what happens with regards to allocation. for a more thorough discussion, I would recommend you read the text "The C++ programming language 4th Edition" by Bjarne Stroustrup in the section about "Abstraction Mechanisms" – ForeverStudent Dec 19 '15 at 16:35
  • The heap memory can grow and shrink. Sometimes, memory is acquired and later released from the operating system kernel. See also [this](http://stackoverflow.com/a/26436766/841108) – Basile Starynkevitch Dec 19 '15 at 16:50

1 Answers1

1

std::vector is a "user-defined type" that is provided by the C++ standard library. It serves as a container that keeps its data dynamically. This is why it can grow with push_back().

let us examine a very simplified version of std::vector: The objects instantiated from this class will only contain integers as data and the size has to be specified at the time of creation

class VectorOfInts {

private:
    int* data; // pointer to where all of the data is stored on heap
    int sz;

public:
    VectorOfInts(int size) :data{new int[size]}, sz{size}  
    {
        for (int i=0; i<sz; ++i) data[i]=0; //initialize all ints to 0 
    }

    ˜VectorOfInts() { delete[] data; } //when the VectorOfInts is destroyed, 
    //we have to remember to release all of our data.

    int getSize() const
    {
        return sz;
    }

    void setValue(int index, const int& value)
    {
        if(index>=sz || index<0) 
            {
                std::cout<<"invalid index\n";
                return;
            }
        //since value is type int which is an integral type, it is copied
        //if we had a vector of struct or class instead, 
        //copy constructor (or suitable move constructor if defined)
        //would have been called. 
        //this is the most crucial part to understand about this code.
        data[index] = value;  
    }
};

As you can see the data is managed internally by the VectorOfInts dynamically on the free store. in fact the size of the class object itself is going to be the same regardless of how big of a container you create via the constructor. This is because your VectorOfInts itself will only have a pointer and an int.

Every single time you set a value, the parameter has to be copied to the dynamic memory that is allocated by the VectorOfInts. for int this is not a big deal, but if we have a vector of large objects (with its own pointers and objects as fields) instead of int, it would be advisable to define a suitable move constructor or consider keeping a vector of pointers instead of the actual object.

This is the essence of how std::vector works. with a few differences including the following:

1- std::vector can grow and shrink with size: instead of size alone, std::vector will keep track of "capacity" which is the total size of the free store allocated and available should the vector grow, as well as "size" which is the actual number of elements held by the vector. If size were to exceed capacity, the vector will reallocate a larger block of memory in heap, copy all of the old data, and free the old memory location.

2- std::vector allows for generic type content: this is not an issue for the implementation because the vector will allocate memory for the size of the object type * the number of elements. this is guaranteed to work because each vector will only contain a specific type of object during its lifetime.

I will now provide a few examples to show exactly where memory goes when dealing with std::vector:

#include <iostream>
#include <vector>

void  helper()
{
    std::vector<int> A; //vector created on the stack
    int a=5;
    int b=6;
    A.push_back(a); //a is copied to another place in memory allocated by A
    A.push_back(b); //same thing with b, they are both copied; 

    std::vector<int>* B = new std::vector<int>(); //B is a pointer only
    //B occupies as much space as any pointer on your machine, but what it points to
    //is a dynamically allocated block of memory that holds a vector
    B->push_back(a); //a is copied to free store
    B->push_back(b); //same thing with b;

    free(B); //this is extremely important, 
             //since B is allocated on the heap, it must be freed
             //or else we will have a memory leak.  
             //the destructor for std::vector is smart
             //it will in turn free its own dynamically allocated memory upon destruction.

} //when this function returns, a, b and A are all destroyed
  // because they fall off the stack
  //A's destructor is called implicitly and the block of memory
  // that is allocated by A is free's by its destructor

and in the main function we have:

int main() {


    helper(); 

    std::vector<int> A;  //created on the stack; 
    A.push_back(1); //the value 1 is copied to dynamic memory by A
    A.push_back(2);
    A.push_back(3);

    std::vector<int> B;  //created on the stack; 
    B.push_back(4); //the value 4 is copied to dynamic memory by B
    B.push_back(5);
    B.push_back(6);

    std::vector<std::vector<int>> C;  //also created on the stack

    C.push_back(A);  //the content of A (including its internal pointers) 
                     //is copied to an area of heap allocated by C
    C.push_back(B);  //same for B, notice that A and B are copied 



    return 0;
} //destructor for A, B and C are called. 
ForeverStudent
  • 2,487
  • 1
  • 14
  • 33