Lets say that I have an object which is expensive to copy, and I cannot move it. I am passing this object to other objects, which it will be a member of. I am not able to take a reference/pointer to the original object due to not knowing the lifetime of it.
If I am to instantiate the original expensive object in a std::shared_ptr, I can avoid deep copying the expensive object and am able to pass the object around with it being more efficient than copying the expensive object. Furthermore, it is nicely cleaned up/destructed when the final instance of it goes out of scope. The issue is, copying a std::shared_ptr is expensive, and I would prefer to avoid this. I can create a wrapper for this behavior which initializes a single instance of the expensive object, reference tracks it, and has proper destruction behavior at the last instance of it going out of scope - but I am not sure if there is a easier/more preferred alternative.
Any help here?
Thanks.
Related
I have some questions about smart pointers implemented in boost library.
Is the only diffrence between shared_ptr and scoped_ptr that scoped_ptr doesn't have copy constructor and shared_ptr has it?
Should i use then scoped_ptr instead of shared_ptr always when object doesn't call copy constructor?
I also doesn't understand idea of shared/scoped array. Can't I just use std::vector instead of it?
Is the only diffrence between shared_ptr and scoped_ptr that
scoped_ptr doesn't have copy constructor and shared_ptr has it?
The difference is more fundamental than that; it has to do with how the smart pointers own the object it points to. What makes smart pointers different from dumb pointers is that the concept of ownership is a core component of their function. The ownership semantics is what differentiates the different kinds of smart pointers.
Because smart pointers "own" the thing they point to, they can do useful things like deleting objects when the smart pointers go away (this is made possible using only the rules of the language; no compiler magic is needed). This way, memory management can be made almost automatic in C++ (despite claims to the contrary, there's very little manual memory management required in modern C++).
shared_ptr implements reference-counting
semantics for
memory management. Multiple shared_ptrs can own a single object. A
shared_ptr going away does not necessarily delete the object it
points to because there may be another shared_ptr owning the
object. The last shared_ptr that owns an object and goes away will
delete the object it owns.
scoped_ptr implements exclusive-ownership semantics. Only one
scoped_ptr can own any one object. When a scoped_ptr goes away,
it will always delete the object it owns (because there's only one
owner). It's typically used as a lightweight RAII mechanism for
objects allocated on the free store.
The array versions (shared_array and scoped_array) have essentially the same semantics, but are designed specifically for arrays e.g. they use delete[] instead of delete, implements the array subscript operator, etc.
shared_ptr and shared_array also allows you to specify a custom deleter, if the default delete behavior is not appropriate for the object. scoped_ptr and scoped_array do not have that ability, since they are quite lightweight compared to shared_ptr and shared_array.
In C++11, the newest and current version of C++, there's also a unique_ptr, which is just like scoped_ptr except that you can transfer the ownership of an object to another unique_ptr. In C++03, an older but more widely supported version of C++, there's auto_ptr which is equivalent to unique_ptr except it was easy to use it in an unsafe manner by accident (which is why it is deprecated in C++11).
Should i use then scoped_ptr instead of shared_ptr always when object
doesn't call copy constructor?
Which one you choose doesn't depend on the presence of the copy-constructor, since shared_ptr and scoped_ptr does not require the object to be copy-constructible. You pick the one depending on the required ownership semantics. If the object will have multiple owners, you use shared_ptr. If the object will only have one owner and the object's existence lasts only within a scope, use scoped_ptr (hence the name scoped_ptr).
I also doesn't understand idea of shared/scoped array. Can't I just
use std::vector instead of it?
std::vector does not implement reference-counting semantics like shared_array does. std::vector is more like scoped_array, but can be copied. When you copy a std::vector, you also copy all of the elements it contains. That's not the case for scoped_array. std::vector also has functions that allow you to manipulate and examine its contents (e.g. push_back, insert, erase, etc.), but is much more heavyweight than scoped_array.
Yes. scoped_ptr does not allow for copies while shared_ptr does. But this "simple" difference makes a world of impact on both the implementation and the usage of the smart pointer.
scoped_ptr is faster and lighter than shared_ptr because no reference counting is involved. shared_ptr will count the number of assignments and not delete the object until all references have expired/gone out of scope.
Now your question regarding vectors implies that you're actually not familiar with the the concept of dynamic allocation and the difference between that and static allocation on the static. You really should look into reading a primer on C(++) and look into the reasons for dynamic allocation and when you need it.
A vector stores a list of objects. A XXX_ptr stores a pointer to a (single) dynamically-allocated object. Apples and oranges.
If you allocate memory, you can put the newly created pointer in a scoped pointer, so that IF the malloc/noew fails, the memory will be freed. This is how I usally uses it, or if it's an object that needs to be allocated on the heap, but that I want to treat it as a stack object in terms of that it will only be alive until the end of the scope.
The shared pointer is if you want to pass the pointer around and allow the object to have multiple owners. Then none of the owners needs to take responibility of the object and they can all just stop using it and be sure that it will be freed correclty. (you don't wanna free an object that you know is used by someone else)
I'd say you're thinking about it the wrong way. The question isn't whether you do call the copy constructor -- it's whether you need to call the copy constructor. In other words, you should be deciding whether to use shared_ptr or scoped_ptr not based on reading your code but based on thinking about object ownership and what objects' lifetimes should be.
Say you have an object that you want to create on the heap, not on the stack, for whatever reason (maybe it's too big to be on the stack, maybe you might want to replace it with a different object at some point, maybe you want it to be initialized late) but its lifetime should never be longer than its containing scope. A common example of this is instance variables in a class: they should often be deleted when the object they are in is deleted. Then, you should use scoped_ptr.
But sometimes you don't know when an object will be safe to delete in advance. For instance, consider an object in a lookup table. You want to return it in response to lookups, but what happens when it's deleted -- could someone still be using the object who looked it up previously? In cases like this, you can use shared_ptr, which shares the objects ownership so that it only gets deleted when nobody has a copy of the pointer anymore.
So why does anyone ever use scoped_ptr instead of shared_ptr? First of all, knowing when the destructor gets called is one of the big advantages of non-memory-managed languages like C++. Maybe the destructor is expensive, or maybe it frees a resource; it's nice to know when these things happen. Also, with shared_ptr, there's the potential for memory leaks if you create a circular reference by accident.
In general, almost every pointer you have should be "owned" -- there should be a single place in your code that news and deletes it. scoped_ptr is great for this; when you want an owned object to be passed around to non-owners you can use a bare pointer. But if you absolutely need an object's ownership to be shared, use shared_ptr -- as long as you're careful to use it correctly!
As for scoped/shared arrays, you can certainly use std::vector, but arrays are cheaper and sometimes people want the performance benefit.
shared_ptr is very different from scoped_ptr. scoped_ptr (which is now standardized in C++11 as std::unique_ptr) is simply a RAII-style smart pointer which takes ownership of a resource and then deallocates the owned resource when the pointer goes out of scope.
A shared_ptr however, may share ownership of the resource with other instances of shared_ptr. The resource stays alive as long as one or more shared_ptr instances own it. This is an automatic memory-management technique, (a form of garbage-collection) known as reference counting. It basically provides the same effect as more advanced garbage collection algorithms, except unlike other garbage collection techniques, it doesn't handle circular references.
As for using std::vector versus boost::scoped_array, yeah - scoped_array doesn't really offer much of an advantage. However, boost::shared_array offers reference counting semantics, just like shared_ptr.
I'm somewhat used to the concept of refcounting through COM and I'm somewhat new to shared_ptr. There are several nice properties with CComPtr that I don't find in shared_ptr, and I'm wondering what are the pattern that prevent missuse of shared_ptr.
The AddRef/Release pattern guarantees there is only one refcount per object (the refcount is stored on the object itself), so it's safe, when you have a random pointer to create a CComPtr around it. On the other hand, shared_ptr has a separate refcount pointer, so it's unsafe to create a new shared_ptr on an object (why does the standard provide a constructor that takes a T* on shared_ptr if it's so unsafe to do?). That seems such a big limitation that I don't understand how one can use shared_ptrs...
A bit corner case: something that I've done in the past with AddRef/Release: I want a container of "weak references" to IFoos (for example a map from URL to IConnection or something). With weak_ptr, I can do that but my collection won't "clean itself up", I'll have expired pointers in it. With Release, I can implement my own weak pointer (a bit of work) that actually cleans up the collection. Is there an alternative with shared/weak_ptr?
Intuitively, there is a performance penalty in doing two memory allocations to create an object (one for the refcount, one for the object) compared to the IUnknown world where you do only one. There is also a locality penalty when accessing the object (assuming that an AddRef is frequently followed by reading the content of the object, which seems likely). Has the cost of both approaches been compared?
why does the standard provide a constructor that takes a T* on shared_ptr if it's so unsafe to do?
Because it's the only way to have shared_ptrs without being intrusive. You can use a shared_ptr on anything. I've even used them on objects from C interfaces, via the use of a deleter object. Things like a cairo_t* and so forth. That way, I never have to free anything ever again.
You can't do that with CComPtr; it only works for IUnknown-style objects.
Also, there is std::make_shared, which creates a shared_ptr directly from an object type and the argument to the constructor. So you never even see the pointer (and it usually allocates the object and its ref-count in one allocation instead of two).
The proper C++ idiom with shared_ptr is very simple: always use make_shared or alloc_shared. If you can't use them, then the proper idiom is to only use the direct naked pointer constructor in tandem with new: shared_ptr<T> pVal{new T{...}}; (or the appropriate function that creates the pointer). Never use it on pointers that you don't know the origin of.
Is there an alternative with shared/weak_ptr?
No, but there are tools to make one if you so desire. Besides the obvious method (run through your collection periodically and remove dead weak_ptrs), you can associate a deleter with the shared_ptr that will (in addition to deleting the pointer) call whatever cleanup function to remove those weak_ptrs.
Intuitively, there is a performance penalty in doing two memory allocations to create an object
See make_shared, above.
There is also a locality penalty when accessing the object (assuming that an AddRef is frequently followed by reading the content of the object, which seems likely).
You don't have to copy the shared_ptr to talk to its contents, nor do you have to bump the reference count to do so.
Now, let's talk about some of the things CComPtr can't do. It's intrusive. It can't be used with arbitrary allocators or deleters (obviously not as important when it's intrusive). It can't do pointer aliasing, where you have a shared_ptr to a member of an object, but the actual reference count is for the object it is a member of. That's a very useful thing to be able to do.
Oh yeah, it's not cross-platform. It's not bound to COM, IUnknown, and all of that overhead.
I have a piece of C++ classes and I have the raw pointer to the objects. The pointer to the object would get passed down to the function. The problem is the underlying function might need to store the pointer at times in an STL container in which pointer to the object would be used later on. If I am not using shared_ptr, I am thinking of adding a bool flag to the class which indicates whether the caller of the function is responsible for deleting the object memory. Would that be fine?
Thanks.
Messy. And rife with many potential bugs that will keep you at work well past midnight on a Saturday.
Be clear and consistent about resource ownership. Either the vector owns the pointers, or some specific function owns the pointers, or smart pointers own pointers. Any mixing of these semantics will have the ultimate result of you tearing your hair out late at night.
The best solution is usually to use a reference-counted smart pointer. (As you probably already know all to well, you can't use std::auto_ptr) Barring that, create a class whose sole purpose in life is to allocate, deallocate and grant access to the vector's contained pointers. Any function that needs the contained object would go through your manager class to get to them.
STL containers will almost certainly take a copy of the object which you insert into it. When the object is removed from the container, the object will be destroyed.
If the default copy constructor is not sufficient (i.e. you need to do a deep copy of the object), you need to ensure you implement your own version which does the copy properly.
scoped_ptr is not copy able and is being deleted out of the scope. So it is kind of restricted shared_ptr. So seems besides the cases when you really need to restrict the copy operation shared_ptr is better to use. Because sometimes you don’t know you need to create a copy of your object or no. So the question is: besides the cases mentioned above, could we consider that shared_ptr is better (or recommended) to use instead of scoped_ptr. Does scoped_ptr work much faster from shared_ptr, or does it have any advantages?
Thanks!
shared_ptr is more heavyweight than scoped_ptr. It needs to allocate and free a reference count object as well as the managed object, and to handle thread-safe reference counting - on one platform I worked on, this was a significant overhead.
My advice (in general) is to use the simplest object that meets your needs. If you need reference-counted sharing, use shared_ptr; if you just need automatic deletion once you've finished with a single reference, use scoped_ptr.
Performance - shared_ptr has more functionality, but also requires an additional allocation (it's also larger, but that rarely matters).
[edit] The second allocation can be avoided by using make_shared, but then weak_ptr will hold the entire entire allocation even after the object is destroyed, which may be a problem for large objects.
Expresison of Intent using scoped_ptr you state more explicitly what you want to do. (In case you wonder - that's a good thing :) ). If you do this correctly, shared_ptr will also indicate "this object is intended to live beyond this scope"
Their intended purpose is different, so, in many cases "shared_ptr vs scoped_ptr" is not a question at all. Sure, you can use a shared_ptr when all you need is a scoped_ptr. But what's the point? shared_ptr has likely a slightly bigger overhead with all the reference counting involved.
scoped_ptr works much faster from shared_ptr. It's right. shared_ptr always allocate memory using your allocator or default allocator.
Scoped_ptr has little in common with shared_ptr, weak_ptr, or unique_ptr because it is only doing very special case of "reference counting". It isn't something you will need very often in well-designed code, but it is a good tool to have available.
Basically, a scoped_ptr isn't a reference-counted thing at all. Rather, it is an object you create on the stack (within the local scope) so that you can do something like this:
//Some enclosing scope- anything set off by "{}" or even a function:
{
scoped_ptr<MyObject> ptr = new MyObject( parameters...);
} // When we hit this closing brace, "ptr" will delete the "MyObject" inside.
You tend to see this pattern more with mutexes and other synchronization primatives- I can declare an "AutoLock" that will lock the mutex passed into it, then unlock it when it deletes to turn the whole "{}" scope into a critical section.
Also notice that a 'scoped_ptr' only ever makes sense when you can't just do a plain-old stack allocation like "MyObject obj(params..)" for some reason. After all, what it is doing is letting you use a heap-allocated object as if it was one on the stack. That tends to be a lot rarer a use case than the reference-counting of shared_ptr & its cousins.
I make a lot of use of boost::scoped_ptr in my code and it is great but I'm currently working with software that uses shared_ptr all over the place and I'm wondering if I'm missing something.
AFAIK a shared_ptr is only useful if different threads are going to be accessing the same data and you don't know what order the threads are going to finish (with the shared_ptr ensuring that the object exists until the last thread has finished with it).
Are there other use cases?
Threads are irrelevant here. What's relevant is whether it's easy to specify a point at which the object is no longer of use.
Suppose several different objects want to use the same object. It might be a pack of data, or for input/output, or some geometric object, or whatever. You want the shared object to be deleted after all of the using objects are deleted, and not a clock cycle before. Rather than figure out which owning object is going to have the longest lifespan (and that can change if you change the program, or perhaps through user interaction), you can use a shared_ptr to force this behavior.
It doesn't matter whether the using objects are in the same or different threads. Objects can have unpredictable lifetimes even if they're all in the same thread.
AFAIK a shared_ptr is only useful if
different threads are going to be
accessing the same data
Well, it's for situations where multiple owners own the same object pointed to by the smart pointer. They may access the smart pointers from different threads, and shared_ptr is usable in that area too, but that's not the main point. If the last owner loses its reference to the object pointed to, the shared_ptr mechanism deletes the object.
You can use a scoped_ptr if all you want to have is a pointer that is deleted when the scope it's created in is left (either by exceptions, by a goto to a place outside, or by normal control flow or some other mechanism). If you use it like that, there is no need to change to shared_ptr.
The difference between scoped_ptr and shared_ptr (and auto_ptr) is mainly copy semantics.
scoped_ptr is for "Resource Allocation Is Initialization" and is not copyable (it cannot be shared with other instances and ownership cannot be transferred)
shared_ptr is for automatic reclamation of memory when shared between multiple parties
auto_ptr is copyable (and transfers ownership when assigned)
Another important difference between shared_ptr and scoped_ptr is that only shared_ptr work with weak_ptr. Weak pointers are used to break cycles of shared pointers, thereby avoiding memory leaks, but weak_ptr can be used for more than that.
Shared and weak pointers may be used to express the difference between owning and non-owning references. Unambiguous ownership of data leads to a cleaner design, so when possible data objects should be owned by one other object through a shared_ptr. All other long-lived references to data objects should be weak pointers, expressing their non-ownership of the data. Each time any non-owning modules access the data, they need to convert the weak_ptr into a shared_ptr, at which point they may find that the data object no longer exists. However, while the non-owning modules access the data object, they hold it through transient shared_ptr, ensuring safe operation even if the owning object were to release the data.
As answered already, shared_ptr is about shared ownership. However, I would argue that shared ownership is generally a bad thing (exceptions exists, such as flyweight pattern) and it is better to identify an owner and put a scoped_ptr there.
A shared_ptr is a smart pointer type that does reference counting. If there's only one owner for the object (frequent case), then scoped_ptr is the right solution. If the object can be shared among multiple parts of the code, then shared_ptr won't let the object be destructed until all references to it have been released.