Shared pointers and raw pointers in same container - c++

I need to populate container with shared pointers and raw pointers at same time.
I guess shared_ptr<T> may be forced to behave like T*, if constructed with no-op deleter and no-op (de)allocator?
Or may be there is universal smart pointer, which binds to different (smart and raw) pointer types?
Or may be shared_ptr can point to one object, but manage lifetime of another (nullptr) object of same type?
Background. I have simple component system. Some components are built-in, no management required, raw pointers will be enough. Other components are external DLLs, they must be attached when requested and detached when removed from "session". For latter I am using wrapper component, that will detach DLL when destroyed.
EDIT: Background updated.
EDIT2: Question updated.
EDIT3: Found straight solution. See my answer if interested.

Generally speaking, no; a container contains exactly one type of object.
You could use some kind of boost::variant<shared_ptr<T>, T*> object as the contained object. But you'd need visitors to access the elements of it. Alternatively, you can give boost::shared_ptr a special deleter object that doesn't actually delete the pointed-to value.

Well, it really depends on what your needs are, and more specifically what you would like to achieve in terms of ownerships:
Should your vector own the shared_ptr<T> ? (or could you just store the pointee ?)
Should your vector own the T* ?
Then there are varied solutions.
Full ownership: just encapsulate the T* in a regular shared_ptr<T>
Partial ownership: as stated, you can just instantiate a shared_ptr<T> with a no-op deleter to wrap the T*
No ownership: just unwrap the shared_ptr<T> using .get() and only store T*

Shared pointer may point to one object, but manage lifetime of another object. Curiously, it may manage nothing, but still point to something. There is special constructor, that accepts another shared pointer, that used to determine which object to share. We can pass empty shared pointer in it.
template <typename T>
std::shared_ptr<T> fake_shared(T *ptr)
{
std::shared_ptr<T> dummy (nullptr); // we have nothing to manage;
std::shared_ptr<T> faked (dummy, ptr); // but we have something to point to;
return faked;
}
Moreover, we can exploit 2 facts. Firstly, this constructor will accept shared pointer of any (other) type. Secondly, std::shared_ptr<void> is legal, and may be used to express our intent more clearly.
template <typename T>
std::shared_ptr<T> fake_shared(T *ptr)
{
std::shared_ptr<void> dummy (nullptr); // we have really nothing to manage;
std::shared_ptr<T> faked (dummy, ptr); // but we have something to point to;
return faked;
}
Alternatively, one may use constructor, that accepts custom deleter, and pass no-op deleter into it.
template <typename T>
std::shared_ptr<T> fake_shared(T *ptr)
{
std::shared_ptr<T> faked (ptr, [](T *){}); // won't be deleted;
return faked;
}
EDIT: Revision, shared void, custom deleter.

Related

Deleters for unique_ptr

There is an array holding unique pointers:
std::array<std::unique_ptr<T, deleter<allocator<T>>>> storage;
where
template<typename ALLOC>
class deleter {
void operator()( void ) { ... }
};
does the deletion as required by unique_ptr. Effectively, it calls the destructor and then deallocates the memory occupied. So far so good.
But there is another deleter:
template<typename T>
class empty_deleter {
void operator()( void ) {}
};
which performs no operation at all - no destruction, no deallocation.
The reason why it exists is to have, in theory, the option to store object owned by such unique_ptr<T, empty_deleter<T>> within the storage array...
The question is - how to achieve that? To make the deleters compatible so that I can assign unique_ptr<T, empty_deleter<T>> to an array of unique_ptr<T, deleter<allocator<T>>> pointers...
I know there are converting constructors within the unique_ptr implementation so in theory, the deleter of one type can be assinged to the unique_ptr being declared with another type but there is a constraint these deleters shall be convertible somehow... could you please advice me how to reach that?
Additionally - once I am successfull in assigning the deleter instance of empty_deleter<T> into unique_ptr<T, deleter<allocator<T>>> whatever how, which operator() is going to be called once the deletion is triggered? The one from empty_deleter<T> or from deleter<allocator<T>>?
You can do this by simply releaseing the pointer from one object and passing it to the other. These two types are incompatible by design. You are not supposed to make them compatible, so you have to do this weird thing to make it work.
Yes, you could make this work by making deleter constructible and assignable from an empty_deleter. But that is bad, because it logically makes no sense.
unique_ptr is supposed to own the object; that's what it is for. You shouldn't want to have a non-owning unique_ptr. If someone gets a unique_ptr, that's supposed to mean they own that thing.
Worse, the very idea of taking a non-owning pointer and claiming ownership of it is highly dubious. If a piece of code does not have the right to delete something (which is what the type unique_ptr<T, empty_deleter<T>> is supposed to mean), it also does not have the right to delegate responsibility for deleting it to someone else.
The code you are trying to write is highly unclear on who owns what (or even what it means to "own" an object) and should be rethought.
As #Nicol Bolas points out, "object owned by such unique_ptr<T, empty_deleter<T>>" is nonsensical. I will answer "how to make a smart pointer that sometimes owns and sometimes doesn't own it's pointee".
None of std::unique_ptr<T, empty_deleter<T>>, std::unique_ptr<T, deleter<allocator<T>>>, nor std::unique_ptr<T, deleter<other_allocator<T>>> are assignable to one another.
If you want to mix and match ownerships of your pointers, you will have to type-erase the deleter. The simplest way is to use the existing function-object type-erasure type, std::function.
template <typename T>
class pmr_unique_ptr : public std::unique_ptr<T, std::function<void(T *)>> {
public:
using unique_ptr::unique_ptr;
// have to supply a deleter
pmr_unique_ptr(pointer) = delete;
pmr_unique_ptr() = delete;
pmr_unique_ptr(std::nullptr_t) = delete;
};
This can be constructed from std::unique_ptr<T, D> so long as D is copyable.

Guarantee Unique objects in factory using unique_ptr

I came across the following code for a factory.
T::create(std::forward<Args>(args)...) returns a pointer to an object created dynamically. So basically if two objects have the same address then they are the same.
unique_ptr guarantees that a single unique_ptr container has ownership of the held pointer. This means that you can't make copies of a unique_ptr.
#pragma once
#include <memory>
#include <vector>
template <typename T>
class PoolFactory {
public:
template <typename... Args>
T *getInstance(Args... args) {
_createdItems.push_back(
std::unique_ptr<T>(T::create(std::forward<Args>(args)...)));
return _createdItems.back().get();
}
~PoolFactory() = default;
public:
std::vector<std::unique_ptr<T>> _createdItems;
};
Question
Suppose we are trying to insert an object that already exists in the vector. Since we are using a factory and IF the object already exists we just want to retrieve it. How will that archtitecture that contains move semantics guarantee that behavior?
Interpreting this code, in this factory your objects are identified by getInstance arguments. The interface also suggests that the callers know both T and its constructor arguments, so that they can construct T themselves.
The only use for this factory is to make each object a singleton.
You need a mapping (args...) -> object, rather than an array, so that first you look up an existing object using args... and create the object if it doesn't exist yet.
You've gotten the "uniqueness" of std::unique_ptr<T> backwards. There is not a magic mechanism such that when you create a std::unique_ptr<T> somehow it checks all the currently existing std::unique_ptr<T> and does something different if one owns the same pointer value.
Instead, it is assumed that you have previously newed a T * and construct a std::unique_ptr<T> from it, or call std::make_unique<T> to new a T and wrap it in a unique_ptr<T> for you. If that assumption is not the case, and the std::unique_ptr<T> is destroyed, your program's behaviour is undefined.
The prohibition on copying then assures you that delete is called exactly once, and often with no additional effort on your part (i.e. the pointee's lifetime is exactly the same as the pointer's lifetime)

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.
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?

C++ pointer container with reference counting

I need a collection in which i can store heap-allocated objects having virtual functions.
I known about boost::shared_ptr, std::unique_ptr (C++11) and boost::ptr_(vector|list|map), but they doesn't solve duplicate pointer problem.
Just to describe a problem - i have a function which accepts heap-allocated pointer and stores it for future use:
void SomeClass::add(T* ptr)
{
_list.push_back(ptr);
}
But if i call add twice with same parameter ptr - _list will contain two pointers to same object and when _list is destructed multiple deletion of same object will occur.
If _list will count pointer which he stores and uses them at deletion time then this problem will be solved and objects will not be deleted multiple times.
So the question is:
Does somebody knows some library with collections (vector,list,map in essence) of pointer with auto-delete on destruction and support of reference counting?
Or maybe i can solve this problem using some other technique?
Update:
I need support of duplicate pointers. So i can't use std::set.
As Kerrek SB and Grizzly mentioned - it is a bad idea to use raw pointers in general and suggests to use std::make_shared and forget about instantiation via new. But this is responsibility of client-side code - not the class which i designs. Even if i change add signature (and _list container of course) to
void SomeClass::add(std::shared_ptr<T> ptr)
{
_list.push_back(ptr);
}
then somebody (who doesn't know about std::make_shared) still can write this:
SomeClass instance;
T* ptr = new T();
instance.add(ptr);
instance.add(ptr);
So this is not a full solution which i wait, but useful if you write code alone.
Update 2:
As an alternative solution i found a clonning (using generated copy constructor). I mean that i can change my add function like this:
template <typename R>
void SomeClass::add(const R& ref)
{
_list.push_back(new R(ref));
}
this will allow virtual method (R - class which extends some base class (interface)) calls and disallow duplicate pointers. But this solution has an overhead for clone.
Yes: std::list<std::shared_ptr<T>>.
The shared pointer is avaiable from <memory>, or on older platforms from <tr1/memory>, or from Boost's <boost/shared_ptr.hpp>. You won't need to delete anything manually, as the shared pointer takes care of this itself. You will however need to keep all your heap pointers inside a shared pointer right from the start:
std::shared_ptr<T> p(new T); // legacy
auto p = std::make_shared<T>(); // better
If you another shared pointer to the same object, make a copy of the shared pointer (rather than construct a new shared pointer from the underlying raw pointer): auto q = p;
The moral here is: If you're using naked pointers, something is wrong.
Realize that smart pointers are compared by comparing the underlying container. So you can just use a std::set of whatever smartpointer you prefer. Personally I use std::unique_ptr over shared_ptr, whenever I can get away with it, since it makes the ownership much clearer (whoever holds the unique_ptris the owner) and has much lower overhead too. I have found that this is enough for almost all my code. The code would look something like the following:
std::set<std::unique_ptr<T> > _list;
void SomeClass::add(T* ptr)
{
std::unique_ptr<T> p(ptr);
auto iter = _list.find(p);
if(iter == _list.end())
_list.insert(std::move(p));
else
p.release();
}
I'm not sure right now if that is overkill (have to check if insert is guaranteed not to do anything, if the insertion fails), but it should work. Doing this with shared_ptr<T> would look similar, although be a bit more complex, due to the lack of a relase member. In that case I would probably first construct a shared_ptr<T> with a do nothing deleter too pass to the call to find and then another shared_ptr<T> which is actually inserted.
Of course personally I would avoid doing this and always pass around smart pointers when the ownership of a pointer changes hands. Therefore I would rewrite SomeClass::add as void SomeClass::add(std::unique_ptr<T> ptr) or void SomeClass::add(std::shared_ptr<T> ptr) which would pretty much solve the problem of having multiple instances anyways (as long as the pointer is always wrapped).

Remove from a std::set<shared_ptr<T>> by T*

I have a set of shared pointers:
std::set<boost::shared_ptr<T>> set;
And a pointer:
T* p;
I would like to efficiently remove the element of set equal to p, but I can't do this with any of the members of set, or any of the standard algorithms, since T* is a completely different type to boost::shared_ptr<T>.
A few approaches I can think of are:
somehow constructing a new shared_ptr from the pointer that won't take ownership of the pointed to memory (ideal solution, but I can't see how to do this)
wrapping / re-implementing shared_ptr so that I can do the above
just doing my own binary search over the set
Construct a shared_ptr<T> from T with a null_deleter (see boost:::shared_ptr FAQ).
struct null_deleter {
void operator()(void const *) const { }
};
size_t remove_ptr_from_set(std::set<boost::shared_ptr<T>> &set, X* x)
{
shared_ptr<X> px(x, null_deleter());
return set.erase(px);
}
That way the types are compatible and you don't have to worry about your temporary shared_ptr deleting any object.
Or, as one of the comments say, if you can change T to inherit from enable_shared_from_this you could get a correct shared ptr from your object.
If the reason for using the set is that you need to efficiently find pointers of type T, then the obvious answer is not to make it a set of shared pointers! Instead, wrap the set in a class which manages the lifetimes of the pointers that the set contains.
You can use boost::ptr_set if you want the set to have ownership of the objects, or boost::reference_wrapper if you just want the set to store references to them. If you use shared_ptr in one place in your code, you will have to use it in all places, or risk terrible crashes (dangling pointers, already deleted objects etc.). The exception is weak_ptr, a pointer that points to an object held by a shared_ptr but does not share ownership.