[try Beta version]
Not logged in

 
shared_ptr doesn't free memory when the counter reaches 0

Nov 13, 2016 at 1:48pm
Hi.

I'm trying to implement my own shared_ptr class for training purposes.
But first, I need to better understand how shared_ptr works.

Consider this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main()
{
   int* ptr = new int{ 5 };

   {
	shared_ptr<int> shared{ ptr };
	cout << shared.use_count() << endl;
   }

    // I expect the resource handled by 'ptr' to be freed here 

    cout << *ptr;

    // Instead, I still get printed 5!

    return 0;
} 


shared_ptr is created inside of a strictly scoped area { } and it's getting the resource pointed by ptr.

After the shared_ptr goes out of scope, the area pointed by ptr should've been released... but apparently that didn't happen.

Why?
Last edited on Nov 13, 2016 at 1:56pm
Nov 13, 2016 at 2:34pm
> I expect ... Instead, I still get printed 5!

Trying to access an object after its lifetime has ended and storage occupied by it has been released engenders undefined behaviour.

To verify that the deleter is called, give the shared pointer a noisy deleter.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <memory>

int main()
{
   int* ptr = new int{ 5 };
   std::cout << "ptr == " << ptr << '\n' ;

   {
       const auto deleter = []( int* p ) { std::cout << "delete " << p << '\n' ; delete p ; } ;
	   std::shared_ptr<int> shared{ ptr, deleter  };
	   std::cout << shared.use_count() << '\n' ;
   }
}

http://coliru.stacked-crooked.com/a/c7dc517dbf5ea195
http://rextester.com/DQHJT75876
Nov 13, 2016 at 8:59pm
Thanks for the reply.

I read that using

 
shared_ptr<Object> p1 = make_shared<Object>(123);


is better than

 
shared_ptr<Object> p1{ new Object(123) };


Can you tell me why?

I already found something on the internet, but I don't get it well
Nov 14, 2016 at 1:06am
The constructor shared_ptr<T>( U* ptr ) ; is exception safe in isolation. If the constructor of the shared pointer throws - typically, because of allocation failure for the shared control block - delete ptr ; is called before the exception is propagated.

However,
code such as f(std::shared_ptr<int>(new int(42)), g()) can cause a memory leak if g throws an exception because g() may be called after new int(42) and before the constructor of shared_ptr<int>. This doesn't occur in f(std::make_shared<int>(42), g()), since two function calls are never interleaved.
http://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared


In addition, there may be (in practice, there is) a performance benefit:
std::make_shared<T> typically allocates memory for the T object and for the std::shared_ptr's control block with a single memory allocation (this is a non-binding requirement in the Standard), where std::shared_ptr<T>(new T(args...)) performs at least two memory allocations.
http://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared
Nov 14, 2016 at 9:55am
alright, what I don't understand is:

make_shared<T> typically allocates memory for the T object and for the std::shared_ptr's control block with a single memory allocation (this is a non-binding requirement in the Standard), wherestd::shared_ptr<T>(new T(args...)) performs at least two memory allocations

how can make_shared() be more efficient than a single constructor?

why does shared_ptr makes two allocations? what are these allocations for?
Nov 14, 2016 at 10:16am
make_shared() is better than the shared_ptr assignment, as it eliminates unnecessary copies.
Nov 14, 2016 at 2:08pm
> why does shared_ptr makes two allocations? what are these allocations for?

Consider: std::shared_ptr<T> ptr(new T(args...) ) ;

One allocation is in the client code, for the object of type T new T(args...)

At least one (typically one) other allocation is required for the shared control block associated with the shared pointer.

The shared_ptr objects that own a resource share a control block. The control block holds:

. the number of shared_ptr objects that own the resource,
. the number of weak_ptr objects that point to the resource,
. the deleter for that resource if it has one,
. the custom allocator for the control block if it has one.

https://msdn.microsoft.com/en-us/library/bb982026.aspx
Topic archived. No new replies allowed.