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

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.


You can use a deleter type that does nothing, but it will need to be passed as an argument to the shared_ptr's constructor

struct DoNothing {
    template <typename T>
    void operator()(T*) const noexcept { }
};

When creating a shared_ptr you will need to create one of these deleters and pass it in the constructor (as you're doing with the lambda). You can make this easier on yourself with an intermediate function

template <typename T>
std::shared_ptr<T> non_deleting_shared_ptr(T* ptr) {
    return {ptr, DoNothing};
}

auto my_input_stream = 
    non_deleting_shared_ptr(
        g_io_stream_get_input_stream(G_IO_STREAM(my_connection.get()));

However the bigger question is why you're using smart pointers when you don't want ownership to be a part of it. You'd almost certainly be better off with just a GAsyncQueue*, unless of course you're in a situation where you have a shared_ptr that needs to free sometimes. Like a data member maybe?