Does storing objects in a std::vector increase the lifetime of the object ?

401 views Asked by At
for (int i = 0; i < 10; i++)
    { 
        nueron temp; // my Class
        _inputNuerons.push_back(temp); // _inputNuerons is a std::vector 
    }

From what I know , C++ deallocates the temp object when it reaches the } bracket of the for loop. But does storing the object in a std::vector make the object usable later on in the program ? Now when I try to access the "temp" nueron outside the for loop , the program crashes.

How can I store my objects in a std::vector such that it is usable later on ?

2

There are 2 answers

2
Elvis Oric On

Your neuron object will be destroyed at the end of for block. You should use dynamic allocation, and store the pointer on that object in vector.

for (int i = 0; i < 10; i++)
{ 
    nueron* temp = new neuron(); // my Class
    _inputNuerons.push_back(temp); // _inputNuerons is a std::vector 
}

_inputNeurons collection should be collection of neuron pointers.

0
2785528 On

How can I store my objects in a std::vector such that it is usable later on ?

The compiler creates a copy constructor for you if you don’t provide your own (and do not delete it).

The body of the compiler-created-copy-constructor is NOT empty, and it will copy all data members of the passed nueron object (temp) to the object which is being created in the element of the vector.

Thus the following works fine:

for (int i = 0; i < 10; i++)
{ 
    Nueron temp; // my Class
    _inputNuerons.push_back(temp); // _inputNuerons is a std::vector 
}
  • new Nueron temp is constructed at the left-brace starting the loop and

  • the object temp is destroyed at the right-brace ending the loop and

  • the push_back copies temp (via compiler provided copy ctor) into the next element of the vector


Here is some code to illustrate the compiler generated default copy ctor.

Note that this default ctor provides a unique value for each Nueron. This is just for fun and to make it easy to see that all elements are copied and initialized with compiler provided default code.

note 1 - You can size and fill a vector in the same line,
and note 2 - you can build an element on your stack, and apply push_back().

Example code:

int seqNum(bool restart=false) // when true restart seqnum
{
   static int SeqNum = 0;
   if(restart) SeqNum = 0; 
   return (SeqNum++);
}

class Nueron
{
public:

   Nueron() : i1(seqNum()) {}  // you provide the default ctor 

   // default dtor - use the compiler provided dtor

   // default copy ctor - use the compiler provided copy ctor

   std::string show()
      {
         std::stringstream ss;
         ss << DTB::digiComma(i1);
         return (ss.str());
      };    

private:
   int i1;
};


void headerShow(std::stringstream& ss)
{
   ss << " vector element size: " << std::setw(5) << sizeof(Nueron) << "  bytes\n" // header
      << "\n"
      << std::setw(15) << "element"
      << std::setw(15) << "vector"
      << std::setw(20) << "bytes stack use"
      << std::setw(24) << "bytes heap use\n"

      << std::setw(15) << "  count"
      << std::setw(15) << "capacity"
      << std::setw(20) << "'sizeof(vector)'"
      << std::setw(24) << "     (element count * element size)\n";
}

void infoShow(std::vector<Nueron>& n, std::stringstream& ss)
{
   ss << std::setw(15) << DTB::digiComma(n.size())    // element count
      << std::setw(15) << DTB::digiComma(n.capacity()) // vector capacity
      << std::setw(18) << DTB::digiComma(sizeof(n))   // bytes stack use
      << std::setw(24) << DTB::digiComma (n.size() * sizeof(Nueron)) // bytes heap use
      << std::endl;
}

void contentShow(size_t               indx,
                 std::vector<Nueron>& n,
                 std::stringstream&   ss,
                 size_t               limit1,
                 size_t               limit2 = 0)
{
   ss << " content " << indx << ": ";

   for (size_t i=0; i<limit1; ++i)
      ss << n[i].show() << "  ";

   if(limit2)
   {
      ss << "...  ";
      for (size_t i=(n.size()-limit2); i<n.size(); ++i)
         ss << std::setw(10) << n[i].show() << "  ";
   }
   ss << std::endl;
}


int t207a(void)
{
   std::cout << "\n============================================= " << "\nt207a():" << std::endl;
   (void)seqNum(true); // restart seq from 0

   std::stringstream ss1;
   std::stringstream ss2;

   std::vector<Nueron> neuron(5);  // default ctor used 5 times
   headerShow(ss1);
   infoShow(neuron, ss1);

   // add 5 more using 'free' copy ctor
   for (size_t i=0; i<5; ++i)
   {
      Nueron temp;             // use ctor
      neuron.push_back(temp);  // use compiler provided copy ctor
   }
   infoShow(neuron, ss1);

   ss2 << "\n";
   contentShow(1, neuron, ss2, 10, 0);

   std::cout << ss2.str() << std::endl << ss1.str() << std::endl;

   // neuron dtor runs here
   return(0);
}

reports:

============================================= t207a():

content 1: 1 2 3 4 5 6 7 8 9 10

vector element size: 4 bytes

    element         vector     bytes stack use         bytes heap use
      count       capacity    'sizeof(vector)'     (element count * element size)
          5              5                24                      20
         10             10                24                      40

edit -

With respect to the other answers that might be interpreted as suggesting putting the vector itself into heap ... I have prepared the following code to illustrate why this is not necessary.

int t207b(void)
{
   std::cout << "\n============================================= " << "\nt207b():" << std::endl;
   (void)seqNum(true); // restart seq from 0

   std::stringstream ss1;
   std::stringstream ss2;

   std::vector<Nueron> neuron; // no elements
   headerShow(ss1);
   infoShow(neuron, ss1);

   size_t cap1 = neuron.capacity();

   // add elements using 'free' copy ctor
   do
   {
      {
         Nueron temp;             // use ctor
         neuron.push_back(temp);  // use compiler provided copy ctor
      }
      size_t cap2 = neuron.capacity();

      if(cap2 != cap1)
      {
         cap1 = cap2;

         infoShow(neuron, ss1);

         if (cap2 > 500000000) break;
         //          12345678
      }

   }while(1);
   contentShow(1, neuron, ss2, 10, 0);

   std::cout << ss1.str() << "\n" << std::endl << ss2.str() << std::endl;
   // neuron dtor runs here
   return(0);
}

With output:

=============================================
t207b(): vector element size: 4 bytes

    element         vector     bytes stack use         bytes heap use
      count       capacity    'sizeof(vector)'     (element count * element size)
          0              0                24                       0
          1              1                24                       4
          2              2                24                       8
          3              4                24                      12
          5              8                24                      20
          9             16                24                      36
         17             32                24                      68
         33             64                24                     132
         65            128                24                     260
        129            256                24                     516
        257            512                24                   1,028
        513          1,024                24                   2,052
      1,025          2,048                24                   4,100
      2,049          4,096                24                   8,196
      4,097          8,192                24                  16,388
      8,193         16,384                24                  32,772
     16,385         32,768                24                  65,540
     32,769         65,536                24                 131,076
     65,537        131,072                24                 262,148
    131,073        262,144                24                 524,292
    262,145        524,288                24               1,048,580
    524,289      1,048,576                24               2,097,156
  1,048,577      2,097,152                24               4,194,308
  2,097,153      4,194,304                24               8,388,612
  4,194,305      8,388,608                24              16,777,220
  8,388,609     16,777,216                24              33,554,436
 16,777,217     33,554,432                24              67,108,868
 33,554,433     67,108,864                24             134,217,732
 67,108,865    134,217,728                24             268,435,460
134,217,729    268,435,456                24             536,870,916
268,435,457    536,870,912                24           1,073,741,828

Summary - for g++ version 4.9.2, on Ubuntu 15.04:

  • column 3 shows that regardless of the number of elements in the vector OR the size of the elements, the stack impact is always only 24 bytes. (i.e. sizeof())

  • column 1 and 2 show the implementations choice for vector growth (i.e. binary)

  • column 4 shows total bytes in the vector. Vector guarantees that all the elements are back to back. In this example the code quit with 500 million element entered, and 1 GByte in (I presume) dynamic memory.

This stack impact is so small, you probably do not want to push the vector to the heap.