Currently I'm using some functions from the glib library. With glib also comes the gio. glib is a C library and therefore I need to delete some structures that I create.
for many of the objects I create a smartpointer eg:
std::shared_ptr<GAsyncQueue> my_queue = std::shared_ptr<GAsyncQueue>(g_async_queue_create(), g_async_queue_unref);
For this creates a shared pointer to an GAsyncQueue
and this is safely destroys the queue on its end of its life.
However, I encounter a problem when I obtain a pointer from the gio library that I should not free. In the following code my_connection
is a GSocketClient which implements (in glib speak) GIOStream.
std::shared_ptr<GInputStream> my_input_stream =
std::shared_ptr<GInputStream> (
g_io_stream_get_input_stream(G_IO_STREAM(my_connection.get()))
);
Because the documentation on GIOStream mentions, that the pointer obtained with g_io_stream_get_input_stream()
should not be freed. That is because it is owned by the my_connection
instance.
I thought about creating a lamda for the destroy object, the second parameter of a shared pointer object. eg auto deleter = [](GInputStream* ptr) {};
and then give that lambda as destroy function to the shared pointer, but that feels a kind of stupid.
A shared pointer can be a class member: In the example above, Jack is shared among three pointers. Shared pointers take the memory management out of the way of programmers. We don’t need to think about deleting a pointer, we don’t need to care which object dies first, or which object outlives others.
If the callee creates a shared_ptr from the raw pointer, the new shared_ptr is independent from the original, and does not control the underlying resource. Use this option when the contract between the caller and callee clearly specifies that the caller retains ownership of the shared_ptr lifetime.
In a typical implementation, a shared_ptr contains only two pointers: a raw pointer to the managed object that is returned by get (), and a pointer to the control block. A shared_ptr control block at least includes a pointer to the managed object or the object itself, a reference counter, and a weak counter.
The point of shared_ptr is to express shared ownership. Anything that does not share in the ownership of an object -- that doesn't have the right to make an object lifetime last longer, and the object lifetime is the union of the shared owners request for object lifetime -- should not use a shared_ptr.
Well, alternative to no-op deleter might be using aliasing shared pointer
template <class U> shared_ptr (const shared_ptr<U>& x, element_type* p) noexcept;
It shares x
, but after get() you'll get back p
.
Discussion: What is shared_ptr's aliasing constructor for?
You probably just don't need a std::shared_ptr
. And you probably don't even need a pointer.
As I read your question and comments, I don't see any point against
auto& my_input_stream = *( g_io_stream_get_input_stream(G_IO_STREAM(my_connection.get())) )
It is true that pointers allow optional data. However, it's also true that it's mostly used the wrong way. Having
void foo( type* ptr)
{
if (!ptr)
throw exception;
}
often doesn't make sense. If the function has to to work on concrete data, allowing a NULL parameter is only useful if you then worry about providing that data. Otherwise, just require a reference (possibly const
) to the object.
Smart pointers are useful; but they're still pointers. Avoiding them altogether, if possible, is even better.
From the comments:
However, a reference must always be initialized
Absolutely. Since C++11 though we've got std::reference_wrapper
which can also be reassinged and stored in containers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With