3

I'm writing a program that will eventually require me to create a vector of unique_ptrs to objects of a custom class. I was getting some memory leaks, so I decided to remove the custom class from the equation and just try it with unique_ptr.

When I try creating a unique_ptr on the stack, there are no leaks. However, creating a vector of unique_ptrs does leak. For fun, I also tried moving a unique_ptr into the vector just to see what happened. My code is below (includes MSVS memory checking):

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#include <vector>
#include <memory>
using namespace std;

int main()
{
    vector<unique_ptr<int>> testvector;
    unique_ptr<int> addMe;

    testvector.emplace_back(move(addMe));
    testvector.clear();

    _CrtDumpMemoryLeaks();
    return 0;
}

When I comment out everything except the creation of "addMe", I get no leaks.
When I comment out everything except the creation of "testvector", I get a memory leak of 8 bytes.
When I comment out the emplace_back of "addme" to "testvector", I get a memory leak of 8 bytes.
When I comment out nothing, I get a memory leak of 12 bytes.
Everything behaves the same when I replace all "unique_ptr" with "shared_ptr".

Am I doing something wrong, or is this to be expected with vectors of smart pointers?

Thanks!

PreacherJayne
  • 217
  • 1
  • 2
  • 9
  • Try putting all your code in braces, so it's scoped such that the vector's destructor will be run before you check for memory leaks. `clear()` will destroy the objects, but the vector may retain the memory (which you can check with `capacity()`) for future use. – Cornstalks Feb 27 '15 at 19:11
  • @Cornstalks Which code should I put in braces? – PreacherJayne Feb 27 '15 at 19:18
  • Everything before `_CrtDumpMemoryLeaks();`. That way you can ensure `testvector` is fully destroyed *before* you check for memory leaks. – Cornstalks Feb 27 '15 at 19:18

1 Answers1

2

As stated in documentation for std::vector::clear()

http://www.cplusplus.com/reference/vector/vector/clear/

Removes all elements from the vector (which are destroyed), leaving the container with a size of 0. A reallocation is not guaranteed to happen, and the vector capacity is not guaranteed to change due to calling this function. A typical alternative that forces a reallocation is to use swap.

Which means, elements get deleted, but the internal storage that std::vector uses does not.

If your compiler supports C++11, then you can use std::vector::shrink_to_fit() to try to make so that capacity is set to size, which after clearing is equal to 0.

http://www.cplusplus.com/reference/vector/vector/shrink_to_fit/

Shrink to fit Requests the container to reduce its capacity to fit its size.

The request is non-binding, and the container implementation is free to optimize otherwise and leave the vector with a capacity greater than its size.

This may cause a reallocation, but has no effect on the vector size and cannot alter its elements.

JustSomeGuy
  • 3,677
  • 1
  • 23
  • 31
  • I think you missed a small part of `shrink_to_fit()`: it's **non-binding**. ["It is a non-binding request to reduce capacity() to size(). It depends on the implementation if the request is fulfilled."](http://en.cppreference.com/w/cpp/container/vector/shrink_to_fit) It's possible that even after `shrink_to_fit()` the vector retains some extra memory. – Cornstalks Feb 27 '15 at 19:16
  • I added that line, but it didn't seem to solve it all. The memory leak decreased from 12 to 8 bytes. – PreacherJayne Feb 27 '15 at 19:17
  • 2
    Put all your stuff in a separate function and call `_CrtDumpMemoryLeaks()` after the function returns. There should be no leaks in this code, it's just that you are still in a frame of the function and there are still objects that didn't get destructed. – JustSomeGuy Feb 27 '15 at 19:19
  • Putting it in a separate function worked, even without the shrinking. I'll definitely keep the shrinking in mind! – PreacherJayne Feb 27 '15 at 19:23