I've got an map shared_ptrs
std::unordered_map<uint64_t, std::shared_ptr<Target>> map;
Is there a way to make them weak_ptrs at some point or do I
have to make something like
std::unordered_map<uint64_t,
std::pair<std::shared_ptr<Target>,
std::weak_ptr<Target>>> map;
and swap them?
Thanks in advance
As people already stated in the comments, you can not do that. A shared_ptr always owns a reference, while a weak_ptr never does. The API of the standard library is explicitly designed in a way that the type tells you whether you currently own a reference or not (and the only thing you should do to access pointees of weak_ptr objects is lock() them, and check the resulting shared_ptr for non-null-ness, so you can (even in a multi-threaded environment) be sure, that you own a reference for yourself while working with the object.
What you could possibly do is have a map of weak_ptr all along, and store a shared_ptr elsewhere as long as you want to keep the object alive. Depending on the design or purpose, the place for the shared_ptr might even be a member variable of the object.
If you use a map of pairs, I would not swap() the pair members, but start with a pair of a shared and a weak ptr referring to the same managed object, and just reset() the shared ptr if it is decided to drop the strong reference, not touching the weak_ptr at that point.
You can always use the weak_ptr or shared_ptr itself as the key in the map. So indeed:
std::map<std::weak_ptr<void>, std::string> information_map;
Would be able to associate strings with any kind of weak ptr, regardless of type. This is because std::less<void*> defines a weak total ordering over all possible pointer values according to the standard.
See also
Advanced Shared Pointer Programming Techniques
How to compare pointers?
Related
I know the general philosophy behind std::unique_ptr<T> and std::shared_ptr<T>. A unique pointer should be used in cases where no other pointer variable will ask for access to the object / primitive data pointed to by the unique pointer. A shared pointer, however, exists for shared/concurrent access to a single resource such as a file.
This all remains true for class data members of pointer types as well of course. However, in particular regards at the implementation level, does this general rule cover all cases?
Assume that you have a class with 3 member variables, all of pointer type. If none of your member functions return a pointer to one of these variables (such as a getter function) then you should declare the member variable to be of type std::unique_ptr<T>. If however, you return one these member variables then you could potentially have a situation where another pointer tries to bind to the same resource. In which case, you should declare that particular member to be of type std::shared_ptr<T>.
This seems to be a logical rule to follow. I guess, what I'm trying to figure out is how to deal with smart pointers when declared as member variables because the decision is more difficult.
A unique pointer should be used in cases where no other pointer variable will ask for access to the object / primitive data pointed to by the unique pointer. A shared pointer, however, exists for shared/concurrent access to a single resource such as a file.
I have a different understanding. The difference between unique and shared ptr is not the access. It is the lifecycle.
unique_ptr doesn't support copy semantics so it always has a single owner.
So I think for a class member variable, it depends on whether you want the class instance to be the only owner of the lifecycle.
Another benefit of unique_ptr is that, in most cases, it has the same size as a raw ptr. So it is smaller and faster than shared_ptr.
It is mentioned in Scott Meyer's book that part of the overhead caused by using shared pointers is that they need virutal function to destroy the pointed object correctly. My question is why? Is this not supposed to be the responsibility of the class of that pointed object to have a virtual destructor?
Is this not supposed to be the reponsibility of the class of that pointed object to have a virtual destructor?
That would be one possible way to design a shared pointer, but std::shared_ptr allows you to do the following, even if Base does not have a virtual destructor:
std::shared_ptr<Base> p { new Derived{} };
It does this by capturing the correct deleter for the argument when the std::shared_ptr is constructed, then calls that when the reference count hits zero rather than just using delete (of course, you can pass your own custom deleter to use instead). This is commonly referred to as type erasure, and this technique is generally implemented using virtual function calls.
I have a class exposing through it's interface add function:
void AddObject(Object *o);
Inside the class I maintain the objects in set<shared_ptr<Object>>.
Since I will create shared_ptr from the received pointer I thought to limit the function argument to only rvalue pointers so to make sure that the user will not delete the pointer I use. And so I'll change the function declaration to:
void AddObject(Object* &&o);
so a typical use will be:
AddObject(new Object())
preventing the user to accidentally delete pointer I hold.
I don't want to to use shared_ptr in the interface because the user is not familiar with shared_ptr.
Do you think my suggestion is a good idea?
I think this is a bad idea. I'm sure there is a reason why shared_ptr c-tor that gets a raw pointer is marked explicit instead of using r-value. In my eyes, It's better to teach the users once about smart pointers or at least teach them about using make_shared/make_unique (which are safer and, in the case of make_shared, more efficient, BTW).
BTW, why shared_ptr and not unique_ptr?
Also, why set? Even if you want to make sure you hold each pointer only once and searching a vector each time doesn't look natural enough in your code, I don't see a reason to hold the pointers sorted instead of using unordered_set.
First of all, this approach will not prevent the user from deleting the pointer. Consider this example
auto obj = new Object();
AddObject(std::move(obj));
delete obj;
Secondly, the amount of steps between calling new and the creation of shared_ptr should be as few as possible. If anything happens inside AddObject before it can create a shared_ptr, the object will never get deleted.
The same applies if there are more arguments to AddObject(). If constructing those fails, you will leak memory.
void AddObject(Object* &&o, SomeOtherObject* x);
AddObject(new Object(), xx()); // if xx() throws, memory leak will occur
Ideally you would "wrap" object creating into shared_ptr construction:
void AddObject(std::shared_ptr<Object> o);
AddObject(std::make_shared<Object>());
Either of the following methods may solve your problem.
You may append more comments for AddObject to tell users that delete the pointer they added is not allowed. This is almost enough.
Or, you could also make Object inherits from a base class which has a private destructor and a method named destroyByOwner.
I have objects that define their own "right of existence". Hence they have the possibility to commit suicide. What happens to a smart pointer that holds it? Will it be dangling or does the pointer recognises that the object destroyed itself and thus point to NULL automatically?
From outside the object I would use ptr.reset(). But what can I do from inside the object?
Terrible, terrible things will happen. The smart pointer will have no idea what just happened and blindly attempt to destroy the object right on cue. This basically means that you have messed up. Objects owning themselves is highly questionable usually, but if you do own yourself, then you must never be owned externally. This directly includes smart pointers.
Proper ownership semantics means that you must have one, and only one, unambiguous owner. This is even true in the case of e.g. shared_ptr, where the object is effectively owned by the reference count.
A self-owning object must be clear about the fact that it owns itself and it is not to be owned externally.
There is a way to do want you want...
The object must keep itself alive using a shared_ptr to itself. If that is the only shared_ptr, then the object can suicide by decrementing the shared_ptr (Probably not a good idea to call reset() having the shared_ptr destroy itself. A better approach is to move the member shared_ptr into a temporary, so the shared_ptr member getting destroyed is not the same shared_ptr as the one causing destruction)
Then, from outside the objects you can use std::weak_ptr, and these will know when the object is destroyed. (Because there is really a metadata object that survives and contains the state, and the weak_ptr checks this before accessing the object.)
It probably makes sense to inherit enable_shared_from_this for such an object, and then make your constructors private and friend make_shared. That way it's impossible for an object instance to exist that is not managed using the internal shared_ptr.
I would suggest using an intrusive pointer. See: Boost intrusive_ptr.
Your object would need an internal reference count. In your implementation of the member function intrusive_ptr_release you could skip clean-up if your object has already 'comitted suicide'.
Is it legal/proper c++0x to leave an object moved for the purpose of move-construction in a state that can only be destroyed? For instance:
class move_constructible {...};
int main()
{
move_constructible x;
move_constructible y(std::move(x));
// From now on, x can only be destroyed. Any other method will result
// in a fatal error.
}
For the record, I'm trying to wrap in a c++ class a c struct with a pointer member which is always supposed to be pointing to some allocated memory area. All the c library API relies on this assumption. But this requirement prevents to write a truly cheap move constructor, since in order for x to remain a valid object after the move it will need its own allocated memory area. I've written the destructor in such a way that it will first check for NULL pointer before calling the corresponding cleanup function from the c API, so that at least the struct can be safely destroyed after the move.
Yes, the language allows this. In fact it was one of the purposes of move semantics. It is however your responsibility to ensure that no other methods get called and/or provide proper diagnostics. Note, usually you can also use at least the assignment operator to "revive" your variable, such as in the classical example of swapping two values.
See also this question