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:
When you call
new SomeType()
... then you need to calldelete pointer
wherepointer
has typeSomeType *
and points to the object allocated by thatnew
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.shared_ptr<Foo>
manages not only theFoo
object, but also a "deleter" which knows how to destruct theFoo
object. When you construct oneshared_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
C++ How to Use Select to See If a Socket Has Closed
Changing the Current Directory in Linux Using C++
Cannot Get Makefile to Build Each Object from Its Corresponding Source
Using a Stl Map of Function Pointers
What Is Indeterminate Behavior in C++ ? How Is It Different from Undefined Behavior
C++ Convert from 1 Char to String
Extending the C++ Standard Library by Inheritance
How to Initialize a Const Field in Constructor
How to Have an Unordered_Map Where the Value Type Is the Class It's In
How to Assert If a Std::Mutex Is Locked
How to Compile SQLite with Icu
How to Correctly Interpose Malloc Allowing for Ld_Preload Chaining
The Simplest and Neatest C++11 Scopeguard
How to Access the Underlying Container of Stl Container Adaptors