Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use a shared_ptr with a pointer to struct that should not be freed

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.

like image 246
hetepeperfan Avatar asked Dec 06 '15 18:12

hetepeperfan


People also ask

Can a shared pointer be a class member?

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.

What happens when a shared_ptr is created from a raw pointer?

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.

How many pointers does a shared_ptr have?

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.

What is the point of shared_ptr in C++?

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.


2 Answers

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?

like image 80
Severin Pappadeux Avatar answered Oct 22 '22 04:10

Severin Pappadeux


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.

like image 25
edmz Avatar answered Oct 22 '22 02:10

edmz