1

So in my job I don't have access to the full std library because....just because (corporate nonsense reasons). I can't use unique_ptr but I have access to shared_ptr and I'm working with c++11. So...

I am using a pre-existing (internal) library function that gets data for me and returns it via a raw point (lets say uint8_t*). And I am want to store this data in my class as a shared_ptr.

According to Will a shared_ptr automatically free up memory?

and http://herbsutter.com/2013/05/29/gotw-89-solution-smart-pointers/

it appears that if I allocate memory on the heap and store this in a shared_ptr, the smart pointer should deallocate the memory (of uint8_t* data) for me. Is this true? Any links to literature would help. Also, from these links it seems that I can't use make_shared because I am "adopting a raw pointer from somewhere else."

class myClass
{
public:
    shared_ptr<uint8_t> iv_data;
    // rest of class
};

other function scope

data_size = getDataSize(...);  // legacy internal function
uint8_t* data = new uint8_t[data_size];
getData(data, data_size); // legacy internal function

myClass object;
object.iv_spd_data = std::shared_ptr<uint8_t>(l_spd_data);

// if scope ends here will I get a memory leak for not freeing data
Community
  • 1
  • 1
Andre Marin
  • 540
  • 1
  • 6
  • 16
  • 1
    Yes, the purpose of std::shared_ptr<> is to automatically free memory allocated with new. However arrays must be deleted with `delete[]` operator not `delete`. You might be able to use `std::shared_ptr` if your library vendor created that specialization. Otherwise you will need to use the custom deleter code from [this answer](http://stackoverflow.com/a/13062069/459615). – Kurt Stutsman Mar 22 '16 at 23:55
  • You might want to move your comment to an answer. I don't see how I could use a custom delete in my example since I am not using new uint8_t[len] to construct the shared_ptr since I am using the raw data directly – Andre Marin Mar 23 '16 at 00:59

2 Answers2

0

I suppose that line: object.iv_spd_data = std::shared_ptr<uint8_t>(l_spd_data); should be: object.iv_data = std::shared_ptr<uint8_t>(l_spd_data);?

shared_ptr can share ownership of pointer with other shared_ptr objects. When the last of shared_ptr owning your pointer is destroyed, then your object to which pointer is pointing to is deleted.

With object.iv_data = std::shared_ptr<uint8_t>(l_spd_data); you are creating temporary shared_ptr and assigning it to object.iv_data. Actually you are sharing ownership on l_spd_data between object.iv_data and temporary shared_ptr. Since temporary shared_ptr is destroyed right after this statement, the only owner is now object.iv_data. When myClass object is destroyed, iv_data is destroyed and l_spd_data deleted.

So you will not get memory leak in this case.

BJovke
  • 1,737
  • 15
  • 18
  • Will the shared_ptr know to use delete[ ] instead of just delete or will I need a custom deleter such as that mentioned by Kurt Stutsman? – Andre Marin Mar 23 '16 at 01:25
  • Default deleter is just `delete`, not `delete[]`. So if you allocated your object with anything else than `new` ( `new[]` is **not** the same as `new`), then you need to pass appropriate custom deleter to `shared_ptr`. – BJovke Mar 26 '16 at 10:52
  • default_delete has a version that uses delete[ ]. http://en.cppreference.com/w/cpp/memory/default_delete – Andre Marin Mar 27 '16 at 04:41
  • _"default_delete has a version that uses delete[ ]"_. This statement is correct but it is completely wrong if you think that somehow shared_ptr will choose the right one for you. default_delete just has a version that uses delete[], but default default_delete is the one that uses plain delete. Still you have to explicitly say that you want to use array version of default_delete. The link you have posted says the same thing. – BJovke Apr 06 '16 at 17:53
  • Yes I agree. Thanks for including more explanation that my answer was lacking. – Andre Marin Apr 09 '16 at 11:43
0

Here is an example of using shared_ptr<> with an array type and custom deleter. I've added some print statements to show the flow through the program. Note you don't need to know the size allocated when deleting, just that the type is an array. Not deleting with delete[] for an allocated array is undefined behavior; that is why the custom deleter is required.

See it in action on ideone

#include <iostream>
#include <memory>
#include <cstdint>

using namespace std;

template< typename T >
struct array_deleter
{
  void operator ()( T const * p)
  { 
    cout << "using delete[]" << endl;
    delete[] p; 
  }
};

int8_t* allocate_func()
{
  cout << "allocating array" << endl;
  return new int8_t[10];
}

int main() {
    int8_t *ptr = allocate_func();
    cout << "creating smart pointer" << endl;
    shared_ptr<int8_t> sptr(ptr, array_deleter<int8_t>());
    cout << "exiting main" << endl;
    return 0;
}
Kurt Stutsman
  • 3,994
  • 17
  • 23
  • Note individual seeing this, if your library supports it, std supports a custom deleter (see std::default_delete for array and non-array types). – Andre Marin Mar 23 '16 at 15:56