Make Shared_Ptr Not Use Delete

make shared_ptr not use delete

Or how about using the stl to provide the wrapper functor - Doug T. description but without the custom caller.

boost::shared_ptr<T> ptr( new T, std::mem_fun_ref(&T::deleteMe) );
boost::shared_ptr<S> ptr( new S, std::ptr_fun(lib_freeXYZ) );

Why does shared_ptr not delete its memory?


Why does shared_ptr not delete its memory?

shared_ptr does delete the memory that it owns when it is the last owner.

I was expecting that the content to which iptr points, would have been deleted, at the end of inner curly braces.

You were expecting correctly.

But output shows 12. Do I miss something?

You're missing that accessing through invalid pointers results in undefined behaviour.

Can I reset shared_ptr without deleting object so that weak_ptr loses a reference to it

std::shared_ptr and std::weak_ptr are made to model the concept of RAII. When you use a std::shared_ptr, you already made the decision that it owns the resource, and that it should release the resource on destruction. The clunkiness you face is due to a rebellion against RAII: you want std::shared_ptr to own the resource but sometimes not really.

The solution is to reframe your object pool as an allocator. Suppose you have

struct obj_t { /* ... */ };

struct pool_t {
obj_t* acquire(); // get an object from the pool
void release(obj_t*); // return the object to the pool
// ...
};

Then your std::shared_ptr will look like

auto d = [&pool](auto p){ pool.release(p); };
std::shared_ptr<obj_t> obj{pool.acquire(), d};

Notably, the resource acquisition always gets paired with its destruction.
Under this model your problem doesn't exist

std::weak_ptr<obj_t> b = obj;
obj = nullptr; // or let obj get destroyed in any other way

if(auto c = b.lock())
// doesn't happen

Delete std::shared_ptr without destroying the managed object?


static std::map m<data *, std::shared_ptr<data> >;

struct container {
data* ptr;
};

void someFunc(container* receiver /* wants to be filled */) {
auto myData = createData(); // returns shared_ptr<data>, I can't do anything about it
receiver->ptr = myData.get();
m[receiver->ptr] = myData;
}


void someOtherFunc(container* receiver)
{
// delete receiver->ptr;
m.erase(receiver->ptr);
}

This elongates the life of shared_ptr through a map.

Should I delete pointer from `new` passed to a function which makes into a `shared_ptr`?

The very idea of a constructor taking a raw pointer is to pass the ownership to std::shared_ptr. So, no, you don't have to delete a raw pointer passed to std::shared_ptr. Doing this will lead to a double deletions, which is UB.

Note that in general passing a raw pointer is dangerous. Consider the following more generalized example:

void addFoo(Foo *foo){
// some code which could throw an exception
auto my_foo = std::shared_ptr<Foo>(foo);
}

If an exception is throw before my_foo is constructed, foo will leak.

If you have no special reason to pass a raw pointer, consider the following alternative:

class Bar {
public:
template<class... Args>
void addFoo(Args... args){
auto my_foo = std::make_shared<Foo>(args...);
}
};

int main() {
auto bar = Bar();
bar.addFoo();
return 0;
}

Here you pass arguments (if you have any) to construct Foo inside addFoo() instead of constructing Foo before invoking addFoo().

Perfect forwarding of args... could be used if it is needed:

    template<class... Args>
void addFoo(Args&&... args){
auto my_foo = std::make_shared<Foo>(std::forward<Args>(args)...);
}

Deleting an untyped shared_ptr

There are a two things at play here:

  1. When you call new SomeType() ... then you need to call delete pointer where pointer has type SomeType * and points to the object allocated by that new expression. There are extensions to this rule with regards to base classes, but inheritance is not involved here, so we'll leave it at that.

  2. shared_ptr<Foo> manages not only the Foo object, but also a "deleter" which knows how to destruct the Foo object. When you construct one shared_ptr from another, then that deleter gets passed on. This allows for "type erasure":

    shared_ptr<Foo> typed = make_shared<Foo>();
    shared_ptr<void> erased = typed;

    Here, erased does no longer have compile time information about the type of the object it points to (that information was "erased"), but still has runtime information (the deleter) about the type of the object.

So to make this work, you need to make sure that you don't violate point 1 above; you need to delete the same type which you allocated with new: a shared_ptr<void>. This shared_ptr<void> needs to be constructed from a shared_ptr<Foo> because then it has a deleter which knows how to destruct a Foo:

void* makeFoo() {
shared_ptr<Foo> with_type = make_shared<Foo>();
shared_ptr<void> type_erased = with_type; // Just for illustration, merge with line below!
return new shared_ptr<void>(type_erased);
}

void destroy(void * ptr) {
shared_ptr<void> * original_ptr = ptr;
delete original_ptr;
}

makeFoo returns a pointer to a shared_ptr<void>. Just with the type info stripped, i.e. as void *.

destroy assumes it is passed such a pointer. Its delete calls the destructor of shared_ptr<void>. Because the shared_ptr<void> has the deleter of the original shared_ptr<Foo>, it knows how to actually destruct the object (Foo).


Side note: OP's code changed quite a few times, but still has basic syntax errors. This is not valid C++!!

delete <shared_ptr<void>*> p;

C++ deleted new operator but can create shared_ptr

std::make_shared use global placement new version of the operator new, by std::allocator::construct

It is necessary to store object and atomic reference counter in the same block of memory, so that shared_ptr template works almost equal to intrusive smart pointer.

You can not prevent std::make_shared to construct a smart pointer.



Related Topics



Leave a reply



Submit