1

I have this class:

class aa
{
public:
  int i = 0;    
  ~aa(){
  std::cout << "killin in the name of" << std::endl;
    }
};

And I want to make a vector of this class. First I thought o reserving the needed size:

int main()
{
    std::vector<aa> vec;
    vec.reserve(2);
    vec[0] = *(new aa());
    vec[1] = *(new aa());
    //use the vector
    
    vec.clear();

    return 0;
}

But the destructor was not called. On the other side, when I fill the Vector using push_back

int main()
{
    std::vector<aa> vec;
    vec.push_back(*(new aa()));
    vec.push_back(*(new aa()));
    //use the vector
    
    vec.clear();

   return 0;
}

I actually get the destructor called.

Why?

ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
Ivan
  • 1,352
  • 2
  • 13
  • 31
  • 2
    Neither `reserve()`, nor `v[0] = ` construct anything. If nothing was constructed, there is nothing to destruct. – Evg Jul 15 '21 at 09:41
  • 1
    `reserve` does not resize the vector the way `resize` does; the vector is still empty and your code has undefined behaviour. (And you have memory leaks. No need for `new` here. `std::vector vec(2);` will accomplish what you want.) – molbdnilo Jul 15 '21 at 09:41
  • 1
    @van Though in the second program the destructor was called nevertheless there are memory leaks. – Vlad from Moscow Jul 15 '21 at 09:43
  • 1
    All you are seeing is one possible symptom (other symptoms are possible) of undefined behaviour. `reserve()` changes the number of elements allocated (i.e. the vector's capacity, not its size), but does not initialise the elements to be valid objects (pointers in your case) so the assignments in the first example to `vec[0]` and `vec[1]` have undefined behaviour. You need to use `resize()` instead of (or in addition to) `reserve()` to ensure the elements are valid, and can be assigned. – Peter Jul 15 '21 at 09:43
  • @VladfromMoscow why are there memory leaks? – Ivan Jul 15 '21 at 09:44
  • 2
    @Ivan Because the dynamically allocated objects were not deleted. The vector deals with copies of these objects. – Vlad from Moscow Jul 15 '21 at 09:45
  • 2
    related: [Why should C++ programmers minimize use of 'new'?](https://stackoverflow.com/questions/6500313/why-should-c-programmers-minimize-use-of-new) – 463035818_is_not_an_ai Jul 15 '21 at 09:46
  • I added a log on the constructor, I see now the weird behaviour! thank you all! – Ivan Jul 15 '21 at 09:46

1 Answers1

3

A std::vector already does this memory management for you.

When you use an std::vector with simple classes like this, you do not need any new or delete calls.

reserve

Under the hood, reserve is just making sure that a chunk of memory is preallocated to hold the specified number of member variables.

resize

Under the hood, resize will actually create n new objects. You do not need to explictly call new.

Your example

The code *(new aa()) will create a new aa object on the heap. When you write vec[0] = *(new aa()); it will attempt to copy the contents of your new object to the object that lives in the address vec[0]. Thus there are 2 distinct objects alive at this point in time ... one object vec[0] at one place in memory, and one object elsewhere in memory.

What's worse is that you have now called new and never deleted that object. You thus have a memory leak.

What you probably want

Almost certainly, what you will want one of these scenarios.

Create a vector, and then resize it to have n elements. Then use those elements:

int main() {
    std::vector<aa> vec;
    vec.resize(2);
    vec[0].i = ...;
    vec[1].i = ...;
    //use the vector
    return 0;
}

push_back elements when you want to add things

int main() {
    std::vector<aa> vec;
    vec.push_back(aa()); // Creates a new aa instance and copies into the vector 

    aa obj;
    vec.push_back(obj); // Copies the existing object's data into a new object in the vector. 
    //use the vector
    return 0;
}

The destructor of vector will delete all of the memory appropriately. No need to explicity clear in this example.

There are more advanced ways that you can use vector, but until you understand this code, you probably should just stick to these basics.

bremen_matt
  • 6,902
  • 7
  • 42
  • 90