34

I realized that after calling vector.clear() which hold shared pointers, the destructors of the object which own by shared_ptr is not being released.

Code example can be seen below . Even vector.clear() being called, destructor called after shared pointer goes beyond the scope.My question is - do I have to delete all smart pointers inside the vector manually by resetting them? Is there any easier way that you can advice ?

Output :   

constructor
I am here
destructor

Code:

#include <vector>
#include <iostream>
#include <memory>

using namespace std;

class A
{
public:
    A(){cout << "constructor" << endl;};
    ~A(){cout << "destructor"  << endl;};
};

int main( )
{
    shared_ptr<A> sharedptr (new A);
    std::vector<shared_ptr<A> > test;
    test.push_back(sharedptr);

    test.clear();
    cout << "I am here" << endl;
}
Guy Avraham
  • 3,482
  • 3
  • 38
  • 50
Kadir Erdem Demir
  • 3,531
  • 3
  • 28
  • 39

4 Answers4

64

you have two copies of shared_ptr<A> in this case, one is the sharedptr variable and the other as an element in the vector.

do this instead

test.push_back(std::move(sharedptr));

note now the original sharedptr has it's internal moved and no longer usable. The other thing is don't do anything at all, this is a perfectly valid usage of of shared_ptr and sharedptr will clean up itself after it goes out of scope.

yngccc
  • 5,594
  • 2
  • 23
  • 33
  • 9
    I would add that in the case shown in the question, I would actually prefer constructing the vector in place in the vector via `emplace_back`, in order to avoid having an accessible named variable (`sharedptr`) whose use would be dangerous after `std::move`. – us2012 Oct 12 '13 at 14:53
  • As @us2012 wrote, this seems like a way to get yourself in trouble. OP's code works exactly as it's supposed to; `shared_ptr` is copied, which increases the reference count, and then correctly calls the destructor when both copies get out of scope. – vgru Feb 07 '21 at 22:33
12

The problem arises when the push_back adds a copy of the shared_ptr to the vector, leaving the original dangling until main exists. If you don't make the shared_ptr in main scope, the problem does not happen. Just avoid making the shared_ptr in main scope. Make it as a temporary right in the push_back call.

Output is now:   

constructor
I am almost there
destructor
I am here

New code:

#include <vector>
#include <iostream>
#include <memory>

using namespace std;

class A
{
public:
  A(){cout << "constructor" << endl;};
  ~A(){cout << "destructor"  << endl;};
};

int main( )
{
  vector<shared_ptr<A> > test;
  test.push_back(shared_ptr<A>(new A));
  cout << "I am almost there" << endl;
  test.clear();
  cout << "I am here" << endl;
  return 0;
}
Guy Avraham
  • 3,482
  • 3
  • 38
  • 50
Fred Jackson
  • 131
  • 3
4

Here sharedptr and the element in vector share the same object which will result in invoking constructor and destructor only once.

daoluan
  • 41
  • 3
1

The reason the destructor isn't called until later is that your variable sharedptr is still in scope until the end of your main(). There are a few ways around this if you really want it cleaned up before then. The most obvious way to fix this is to only use sharedptr in a quick block scope:

int main( )
{
    std::vector<shared_ptr<A> > test;
    {
      shared_ptr<A> sharedptr (new A);
      test.push_back(sharedptr);
    }
    test.clear();
    cout << "I am here" << endl;
}

Or alternatively, never create the sharedptr variable at all:

int main( )
{
    std::vector<shared_ptr<A> > test;
    test.push_back( shared_ptr<A>(new A) );
    test.clear();
    cout << "I am here" << endl;
}
Drew Harwell
  • 134
  • 2
  • 6