I'd like to wrap raw pointer member to some smart pointer to prevent deleting inside a developing class. Owner of the object under pointer is outside of class. So, looks like boost::shared_ptr and std::auto_ptr does not fit. The following is a reduced example:
class Foo {
boost::weak_ptr<Bar> m_bar;
public:
void setBar(const Bar *bar) { // bar created on heap
m_bar = bar; // naturally compilation error
}
};
Of course, it induces compilation error. What is a correct way to initialize weak_ptr from a raw pointer (if exist)?
You can't do that, you can only create a weak_ptr out of a shared_ptr or another weak_ptr.
So the idea would be that the owner of the pointer hold a shared_ptr instead of a raw pointer, and everything should be ok.
The only way to do it is by getting hold of a shared_ptr or weak_ptr that owns the pointer, otherwise the weak_ptr has no way to find the existing owner in order to share ownership with it.
The only way to get a shared_ptr from a raw pointer that is already owned by another shared_ptr is if Bar derives from enable_shared_from_this<Bar>, then you can do
m_bar = bar->shared_from_this();
The purpose of a weak pointer is to be unable to use the raw pointer if it had been deleted. However, if you have a raw pointer, the weak pointer has no way to know that it was deleted. Instead, you must have a shared_ptr somewhere which "owns" the raw pointer. Then you can create a weak_ptr which references the shared_ptr.
When the shared_ptr goes out of scope and is the last "strong" smart pointer, it will automatically delete the raw pointer. Then, when you try to lock the weak_ptr, it will see that there is no "strong" pointer remaining and therefore the object does not exist.
Everything you've said seems perfectly reasonable, except for one thing:
void setBar(const Bar *bar)
This shouldn't take a raw pointer. It should take a weak_ptr ideally, or possibly a shared_ptr if you have some compelling argument.
The actual owner of the object in question should construct the weak_ptr and than call setBar with that. This preserves the ownership semantics. It looks like what you're doing is having the owning object take a raw pointer and pass that to setBar. This creates a semantic gap in the ownership of the object.
Pass shared pointer instead of raw pointer, and create your weak pointer from that shared pointer. This is really the only way if owner of the pointer is outside of a class.
Related
I have a command pattern class with a pointer to another object (let's call it Duck). Its subclasses will use Duck, but to control and track when Duck is used (for debugging) I made Duck private and subclasses can only get it through a method getDuck();
class Command
{
private:
Duck* target;
public:
//Parametrized Constructor
Command(Duck* _target);
Duck* getDuck() { return target; }
...
};
I recently learned in Effective C++ by Scott Myers the horrors of returning a pointer. I tried just returning the dereferenced version, but that caused a copy of target to be returned. Should I (and is there a way to) simply return a Duck object instead of a pointer to it?
Conceptually, there are two kinds of pointers: owning and non-owning.
An owning pointer indicates that the holding object/function owns the allocation and is responsible for deleting the object.
A non-owning pointer is a "borrowed" object; the holding object/function does not own the object and is not responsible for cleaning it up.
Ideally, this manifests in the C++ type system since C++11 in the following ways:
std::unique_ptr<T> is a unique-ownership pointer to a T object. Exactly one object/function can own the allocation.
std::shared_ptr<T> is a shared-ownership pointer to a T object. Many objects/functions share ownership of the allocation, and the target object is deleted only when all of them are done with it.
T * is a non-owning pointer. This is returned by functions to indicate that the caller does not own the object. The caller is not expected to delete the object; indeed, the caller may not delete it. The caller is expected not to use the pointer once the owning object/function destroys the target object.
There is nothing inherently wrong with returning a raw pointer, though I would only return a pointer when the function needs to conditionally give access to an object it owns:
T *: The function is returning a non-owning handle to an object, but it might not have an object so could return nullptr. T * is "optional, non-owning object handle."
T &: The function is returning a non-owning handle to an object, and it will always have such an object to return. T & is "mandatory, non-owning object handle."
Note that not all standard library facilities will respect these guidelines; indeed not all of them can! new T must return a T * because that's how it's defined to work. These are guidelines that you should follow in your application.
What happens if a C/C++ API returns a raw pointer from an internally used shared_ptr, then the shared_ptr gets "deleted"? Is the raw pointer still valid? How can the API developer clean up the raw pointer when it's not in their control anymore?
As an example:
MyClass* thisReturnsAPtr()
{
std::shared_ptr<MyClass> aSharedPtr = std::make_shared<MyClass>(MyClass);
return aSharedPtr.get();
}
If there are no other shared_ptr around anymore that still hold a reference to the object and, thus, keep the object alive, then the object will be destroyed, the memory freed, and any still existing pointer that pointed to that object will become a dangling pointer.
In your example above, the pointer returned by the function thisReturnsAPtr is guaranteed to be an invalid pointer…
It can sometimes be useful to think of smart pointers as a delayed delete mechanism. What I mean by that is that if you allocate a class and give it to a smart pointer you are basically asking the smart pointer class to delete that pointer sometime in the future. For a shared_ptr that time in the future is when no more shared_ptrs exist for it.
Applying this to your code, you create a shared_ptr. You then return the raw pointer. Then your function ends and the only shared_ptr to that pointer gets destroyed and so the underlying class is deleted.
This makes your question "If I new a class and delete it then return the original pointer what happens". Which is a lot easier to answer and the answer to that is "badness". There are many answers to this question on stack overflow - such as C++ delete - It deletes my objects but I can still access the data?
"What happens to a raw pointer if it's shared_ptr is deleted?" - Nothing. It just becomes invalid to subsequently use that pointer.
"a C/C++ API returns a raw pointer from an internally used shared_ptr, then the shared_ptr gets "deleted"? Is the raw pointer still valid?"
No. It is not valid to then use the raw pointer. And the raw pointer does not change (to nullptr) to indicate that the pointed-to object has been deleted.
It is your responsibility to ensure, that if something like that happens, you do not use the raw pointer after it has been invalidated. How you do that is up to you - the language doesn't care/help you.
Using the raw pointer after the object it points to has been deleted, is Undefined Behaviour.
My question is that what are the various ways in which get() member from the shared_ptr class can be used? And why can't we use delete to delete it?
If you had a function taking a raw pointer
void f(T *t); // non-owning pointer
And you had a smart pointer to a T object, you could pass it to that function by using get()
std::shared_ptr<T> sp{new T}; // or unique_ptr
//f(sp); // no good, type mismatch
f(sp.get()); // passes the raw pointer instead
APIs taking raw pointers are common, and still useful. I'd suggest you watch this part of Herb Sutter's talk from CppCon 2014, and probably the parts around it.
You should not attempt to delete this pointer, the smart pointer classes assume you will not do anything like that, and will still free the managed object in their own destructors when the time comes (after all, how would it know you deleted it?).
The smart pointer's job is to manage the object and delete it at the right time, if you want to manually manage the lifetime of the object (not usually recommended) then use a raw pointer.
If you do want to assume ownership of a unique_ptr you can do so by calling release().
Usually you would use get() when you need to pass a raw pointer to an API that accepts such a pointer.
The shared_ptr class manages the ownership of the pointer, so it will automatically delete the owned memory when the lifetime of the smart pointer ends. If you try to delete the memory yourself then when the shared_ptr tries to deallocate you will wind up with undefined behavior.
Example code:
#include<memory>
#include<iostream>
int main()
{
std::unique_ptr<int> intPtr{new int(3)};
int* myPtr = intPtr.get();
*myPtr = 4;
std::cout<<"New result for intPtr: "<< *intPtr.get()<<std::endl;
}
Doesn't this defeat the whole purpose behind std::unique_ptr ? Why is this allowed?
Edit: I thought the whole purpose behind std::unique_ptr was to have sole ownership of an object. But this example, the object can be modified through another pointer. Doesn't this defeat std::unique_ptr's purpose?
While Smart pointers manage the lifetime of an object being pointed to, it is often still useful to have access to the underlying raw pointer.
In fact if we read Herb Sutter's GotW #91 Solution: Smart Pointer Parameters he recommends passing parameters by pointer or reference when the function is agnostic to the lifetime of the parameter, he says:
Pass by * or & to accept a widget independently of how the caller is
managing its lifetime. Most of the time, we don’t want to commit to a
lifetime policy in the parameter type, such as requiring the object be
held by a specific smart pointer, because this is usually needlessly
restrictive.
and we should pass by unique_ptr when the function is a sink:
Passing a unique_ptr by value is only possible by moving the object
and its unique ownership from the caller to the callee. Any function
like (c) takes ownership of the object away from the caller, and
either destroys it or moves it onward to somewhere else.
and finally pass a unique_ptr by reference when we can potentially modify it to refer to a different object:
This should only be used to accept an in/out unique_ptr, when the
function is supposed to actually accept an existing unique_ptr and
potentially modify it to refer to a different object. It is a bad way
to just accept a widget, because it is restricted to a particular
lifetime strategy in the caller.
Of course, we are required to get the underlying pointer if we have to interface with C libraries that take pointers.
In your specific example:
int* myPtr = intPtr.get();
There is no transfer of ownership to another smart pointer so there are no problems as long as you don't attempt to delete the pointer via myPtr. You can transfer ownership to another unique_ptr by moving it:
std::unique_ptr<int> intPtr2( std::move( intPtr ) ) ;
The example you have shown does not defeat the purpose of std::unique_ptr, which is to maintain ownership of memory allocation and deallocation. The line std::unique_ptr<int> intPtr{new int(3)} allocates a new int and takes ownership of it.
The line *myPtr = 4 does not change that ownership, it is merely assigning a value to the content of the int, via a pointer retrieved by std::unique_ptr::get(). The std::unique_ptr still owns the allocated memory for the int.
This doesn't defeat the purpose of unique_ptr at all. The type of smart pointer determines the ownership semantics, but there may be a case where you need to use the underlying object. For example you have an object owned by a unique_ptr but need to call a method that expect the object by reference. You can then dereference the .get() pointer to get the reference object to pass to the method.
What you shouldn't do is store the obtained pointer in a way that acquires ownership. This is one of the cases where the language gives you tools to work properly and if you take the raw pointer and store a second ownership to it then that's a problem with the use of the tool.
Get just allows you to obtain the raw pointer. Otherwise, you wouldn't be able to use a pointer-based API when you have a unique_ptr, as the only alternative is release, which would make the unique pointer useless. So you get get, which allows using pointer-based APIs without forcing everyone to use an unique_ptr. Without get, you could only call -> and * on the pointer, but if you have a primitive type, that would kind of defeat of having an unique_ptr in the first place.
This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
pimpl: shared_ptr or unique_ptr
smart pointers (boost) explained
Could someone explain differences between shared_ptr and unique_ptr?
Both of these classes are smart pointers, which means that they automatically (in most cases) will deallocate the object that they point at when that object can no longer be referenced. The difference between the two is how many different pointers of each type can refer to a resource.
When using unique_ptr, there can be at most one unique_ptr pointing at any one resource. When that unique_ptr is destroyed, the resource is automatically reclaimed. Because there can only be one unique_ptr to any resource, any attempt to make a copy of a unique_ptr will cause a compile-time error. For example, this code is illegal:
unique_ptr<T> myPtr(new T); // Okay
unique_ptr<T> myOtherPtr = myPtr; // Error: Can't copy unique_ptr
However, unique_ptr can be moved using the new move semantics:
unique_ptr<T> myPtr(new T); // Okay
unique_ptr<T> myOtherPtr = std::move(myPtr); // Okay, resource now stored in myOtherPtr
Similarly, you can do something like this:
unique_ptr<T> MyFunction() {
unique_ptr<T> myPtr(/* ... */);
/* ... */
return myPtr;
}
This idiom means "I'm returning a managed resource to you. If you don't explicitly capture the return value, then the resource will be cleaned up. If you do, then you now have exclusive ownership of that resource." In this way, you can think of unique_ptr as a safer, better replacement for auto_ptr.
shared_ptr, on the other hand, allows for multiple pointers to point at a given resource. When the very last shared_ptr to a resource is destroyed, the resource will be deallocated. For example, this code is perfectly legal:
shared_ptr<T> myPtr(new T); // Okay
shared_ptr<T> myOtherPtr = myPtr; // Sure! Now have two pointers to the resource.
Internally, shared_ptr uses reference counting to track how many pointers refer to a resource, so you need to be careful not to introduce any reference cycles.
In short:
Use unique_ptr when you want a single pointer to an object that will be reclaimed when that single pointer is destroyed.
Use shared_ptr when you want multiple pointers to the same resource.
unique_ptr is the light-weight smart pointer of choice if you just have a dynamic object somewhere for which one consumer has sole (hence "unique") responsibility -- maybe a wrapper class that needs to maintain some dynamically allocated object. unique_ptr has very little overhead. It is not copyable, but movable. Its type is template <typename D, typename Deleter> class unique_ptr;, so it depends on two template parameters.
unique_ptr is also what auto_ptr wanted to be in the old C++ but couldn't because of that language's limitations.
shared_ptr on the other hand is a very different animal. The obvious difference is that you can have many consumers sharing responsibility for a dynamic object (hence "shared"), and the object will only be destroyed when all shared pointers have gone away. Additionally you can have observing weak pointers which will intelligently be informed if the shared pointer they're following has disappeared.
Internally, shared_ptr has a lot more going on: There is a reference count, which is updated atomically to allow the use in concurrent code. Also, there's plenty of allocation going on, one for an internal bookkeeping "reference control block", and another (often) for the actual member object.
But there's another big difference: The shared pointers type is always template <typename T> class shared_ptr;, and this is despite the fact that you can initialize it with custom deleters and with custom allocators. The deleter and allocator are tracked using type erasure and virtual function dispatch, which adds to the internal weight of the class, but has the enormous advantage that different sorts of shared pointers of type T are all compatible, no matter the deletion and allocation details. Thus they truly express the concept of "shared responsibility for T" without burdening the consumer with the details!
Both shared_ptr and unique_ptr are designed to be passed by value (with the obvious movability requirement for the unique pointer). Neither should make you worried about the overhead, since their power is truly astounding, but if you have a choice, prefer unique_ptr, and only use shared_ptr if you really need shared responsibility.
unique_ptr
is a smart pointer which owns an object exclusively.
shared_ptr
is a smart pointer for shared ownership. It is both copyable and movable. Multiple smart pointer instances can own the same resource. As soon as the last smart pointer owning the resource goes out of scope, the resource will be freed.
When wrapping a pointer in a unique_ptr you cannot have multiple copies of unique_ptr. The shared_ptr holds a reference counter which count the number of copies of the stored pointer. Each time a shared_ptr is copied, this counter is incremented. Each time a shared_ptr is destructed, this counter is decremented. When this counter reaches 0, then the stored object is destroyed.