I am using few library functions that return a pointer created either using malloc or new.
So, I have my own customer deallocator based on what type of allocation was used.
E.g
shared_ptr<int> ptr1(LibFunctA(), &MallocDeleter); //LibFunctA returns pointer created using malloc
shared_ptr<int> ptr2(LibFunctB(), &newDeleter); //LibFunctB returns pointer created using new
Now, I understand this is a very naive use of deallocator above but what other scenarios is it heavily used for ?
Also, how can one use a customer allocator ? I tried to assign a custom allocator as below but now how do I actually get it called ? Where does this kind of feature help ?
shared_ptr<int> ptr3(nullptr_t, &CustomDeleter, &CustomAllocator); //assume both functs are defined somewhere.
I don't see anything "naive" about using deleters that way. It is the main purpose of the feature after all; to destroy pointer objects that aren't allocated using the standard C++ methods.
Allocators are for when you need control of how the shared_ptr's control block of memory is allocated and deleted. For example, you might have a pool of memory that you want these things to come from, or if you're in a memory-limited situation where allocation of memory via new is simply not acceptable. And since the type of the control block is up to shared_ptr, there's no other way to be able to control how it is allocated except with some kind of allocator.
Custom deleters for shared_ptr are very useful for wrapping some (usually) C resource that you need to later call a freeing function on. For example, you might do something like:
shared_ptr<void> file(::CreateFileW(...), ::CloseHandle);
Examples like this abound in C libraries. This saves from having to manually free the resource later and take care of possible exceptions and other nasties.
I think the custom allocator will be used to allocate space for the "shared count" object, that stores a copy of the deallocator (deleter) and the reference counter.
As for what a custom deleter can be used for...
One use was already mentioned: make shared_ptr compatible with objects that must be deleted by some special function (like FILE which is deleted by fclose), without having to wrap it into a helper-class that takes care of the proper deletion.
Another use for a custom deleter is pools. The pool can hand out shared_ptr<T> that were initialized with a "special" deleter, which doesn't really delete anything, but returns the object to the pool instead.
And one other thing: the deleter is already necessary to implement some shared_ptr features. E.g. the type that's deleted is always fixed at creation time, and independent of the type of the shared_ptr that's being initialized.
Vou can create a shared_ptr<Base> by actually initializing it with a Derived. shared_ptr guarantees that when the object is deleted, it will be deleted as a Derived, even if Base does not have a virtual dtor. To make this possible, shared_ptr already has to store some information about how the object shall be deleted. So allowing the user to specify a completely custom deleter doesn't cost anything (in terms of runtime performance), and doesn't require much additional code either.
There are probably dozens of other scenarios where one can make good use of the custom deleter, that's just what I have come up with so far.
Related
Is it possible to use both a custom allocator and a custom deleter at the same time for std::shared_ptr? It seems to me that there is no way of doing so, since std::allocate_shared doesn't take a deleter. And also, the only sensible signature of the deleter would be something like void deleter(T*, const Alloc&), instead of just void deleter(T*).
Is there any way to work around this limitation?
Yes, you can do that, but make sure you understand what's going on. The deleter's purpose is to destroy the object. The allocator is used for internal book-keeping structures.
std::shared_ptr<T> sp(new T(args...), std::default_delete<T>(), myalloc);
The point of make_shared and allocate_shared is that they take care of constructing the object for you, so you don't specify a deleter — they use their own deleter that's appropriate for the way they obtained resources (i.e. respectively via operator new and the provided allocator).
You can of course create your own allocator deleter (like this one or the one proposed here) to pass into the above constructor to go along with an allocator-allocated object, and then also use the allocator (or a different one!) for the book-keeping.
There's something to be said for not using make_shared/allocate_shared in situations where either you have long-lived weak pointers or where binary size matters.
You can use a separate allocator and deleter; there are shared_ptr constructors that take both.
But you cannot do this through allocate_shared. The reason being that the allocator is for allocating/deallocating the shared storage. The deleter is for destroying the object being managed and freeing its storage.
Since allocate_shared allocates the object being managed in the same storage as the shared storage itself, it no longer makes sense for the two operations to be separate. And therefore, you must use the same object for both processes. The allocator allocates and deallocates the single allocation, and it takes care of construction/destruction duties for the T being created and destroyed.
From the research I have done, it sounds like std::make_shared is the preferred way of constructing a std::shared_ptr. Specifically because:
It performs only one memory allocation, compared with using new, which performs at least two.
If the ctor passed to make_shared throws, then it won't leak, as it will with new.
My question is, assuming that I want a shared_ptr, should I always use make_shared, or are there cases where new is preferred?
As the counter and the object share the same allocation, they also share the same deallocation.
The counter has to persist until the last shared_ptr and weak_ptr go away. If you have a large object (or many small objects) with long-lasting weak_ptrs, this can cause memory contention if you allocate the shared_ptrs via make_shared.
Second, if you have a 3rd party API that hands you a pointer or a resource handle, and possibly has its own dispose functionality, make_shared is neither appropriate nor possible to use in every case. Creating your own make_ functions can keep the messy details out of the way lets you deal with this problem, and deals with the exception corner case as well.
Finally, while shared pointers are awesome, they are also overly powerful. Quite often I want a unique_ptr or even a boost::scoped_ptr, or an intrusive reference counting pointer, or the like to represent ownership. shared_ptr should be used only when the situation actually involves shared ownership of the resource: using it willy nilly because it is "easy" tends to end up with the resource equivalent of spaghetti code.
You may have to deal with legacy code which returns a dynamically allocated object. In which case, you would need to use the std::shared_ptr<T> ctor with the pointer parameter. It's not preferable to using std::make_shared but it does allow you to use all the std::shared_ptr<T> goodness with legacy code.
I know that this is not strictly equivalent to using the std::shared_ptr<T> ctor with new directly but it is a valid use case of std::shared_ptr<T> where make_shared cannot be utilised.
I am a bit uncertain about the interpretation of your question. I am assuming that it is justified to use a shared_ptr<T>; I can only second Yakk on the reasons why you wouldn't want to use shared_ptr in the first place.
There is one situation where you cannot use make_shared or allocate_shared to construct the shared_ptr but you need to use the corresponding ctor: If you need to pass in a custom deleter, see (3) and (4) at the ctors of shared_ptr.
I ran into problems using make_shared on a class with a private constructor (from a static factory method). I don't think there's an easy solution to this.
should I always used make_shared, or are there cases where new is
preferred
make_shared is not allowed when we are storing a naked pointer in shared_ptr allocated by someone else. and it can only call public constructors. However there are some reports in some compiler about accessing protected constructor using make_shared like this.
I couldn't find an exact answer to this question and hence posting here.
When I think of vector, it needs to build objects in a contiguous memory location. This means that vector keeps memory allocated and have to do an in-place construction (=placement new) of objects being pushed into it. Is this a valid assumption? Also, does this mean the container is manually invoking the destructor rather than calling delete? Are there any other assumptions that I am missing here? Does this mean I can assume that even a custom written new for the object may not be invoked if I chose to write?
Also it makes sense for a list to use a new and delete as we don't need the continuous memory guarantee. So, is this kind of behavior is what drives how allocators behave? Please help.
Thanks
This means that vector keeps memory allocated and have to do an in-place construction (=placement new) of objects being pushed into it. Is this a valid assumption?
Yes
Also, does this mean the container is manually invoking the destructor rather than calling delete?
Yes
Are there any other assumptions that I am missing here? Does this mean I can assume that even a custom written new for the object may not be invoked if I chose to write?
Yes. Consider that even in linked lists, the container will not allocate an instance of your type, but rather a templated structure that contains a subobject of the type. For a linked list that will be some complex type containing at least two pointers (both links) and a subobject of your type. The actual type that is allocated is that node, not your type.
Also it makes sense for a list to use a new and delete as we don't need the continuous memory guarantee.
It does, but it does not new/delete objects of your type.
So, is this kind of behavior is what drives how allocators behave?
I don't really understand this part of the question. Allocators are classes that have a set of constraints defined in the standard, that include both the interface (allocate, deallocate...) and semantics (the meaning of == is that memory allocated with one can be deallocated with the other, any other state in the class is irrelevant).
Allocators can be created and passed onto containers for different reasons, including efficiency (if you are only allocating a type of object, then you might be able to implement small block allocators slightly more efficient than malloc --or not, depends on the situation).
Side note on placement new
I have always found interesting that placement new is a term that seems to have two separate meanings. On the one side is the only way of constructing an object in-place. But it seems to also have a complete different meaning: construct this object acquiring memory from a custom allocator.
In fact there is a single meaning of placement new that has nothing to do with constructing in-place. The first is just a case of the second, where the allocator is provided by the implementation (compiler) as defined in 18.4.1.3 and cannot be overloaded. That particular version of the overloaded allocator does absolutely nothing but return the argument (void*) so that the new-expression can pass it into the constructor and construct the object on the memory (not) allocated by the placement new version that was called.
You're very close to being perfectly correct. The way that the vector (and all the other standard containers) do their allocation is by using the std::allocator class, which has support for constructing and destructing objects at particular locations. Internally, this uses placement new and explicit destructor calls to set up and destroy objects.
The reason I say "very close to being perfectly correct" is that it's possible to customize how STL containers get their memory by providing a new allocator as a template argument in lieu of the default. This means that in theory it should be possible to have STL containers construct and destruct objects in different ways, though by default they will use the standard placement new.
In my class the constructor is private and I added a static method "CreateMyClassPtr" that uses the constructor and returns a share_ptr of it.
Is it the correct implementation?
Do you think I even have to make sure that shared_ptr will be used? Should I maybe leave it to the user to decide?
If you aren't holding onto any copies of it but you want the user to delete the pointed-to-object using delete then you can return a std::auto_ptr by value. It doesn't add any dependencies (auto_ptr is part of the standard) and it makes your interface clearly communicate the requirement that the object needs to be deleted.
If the user wants to, then they can release the pointer and do things manually or move it into their shared smart pointer framework.
Is the element really shared? That is, after creation, do you keep a pointer into the object for your own purposes or are you doing this just to avoid user memory leaks?
If the memory is not actually shared I would not use a shared_ptr. Note that by using shared_ptr as your return type you are forcing the use of both dynamic allocation and a particular implementation of a smart pointer, but limiting the use of the stack for your type and other smart pointer types that might be more appropriate (you cannot extract membership from a shared pointer)
If you really want to make sure that the call will not leak (that is, if the user calls your function the returned memory will be handled 'somehow', you could use std::auto_ptr or boost::unique_ptr (the last one being unstandard even in C++0x). Both solutions allow calling code to extract the pointer from the smart pointer and use a different approach to memory management (even if it can be cumbersome in some cases).
struct type {
std::auto_ptr<type> create();
};
std::auto_ptr<type> ap = type::create();
std::shared_ptr<type> sp( type::create().release() );
type::create(); // will not leak memory
type *rp = type::create().release(); // user specifically requested a raw pointer!
That will work, yes. However, are you sure you need it? There are circumstances where this is appropriate, but you are really limiting your options when you do so. There are other forms of smart pointers users might want to utilize, not to mention that you are eliminating stack-based allocation as an option when you hide your constructors that way.
If you going to expose your class to clients, then don't force them to use shared pointers. They know that they create an object and they are responsible for its deletion.
They then easily can write
myfavorite::api::shared_ptr<Class> object(Class::create());
or
std::auto_ptr<Class> object(Class::create());
Are there any downsides with using make_shared<T>() instead of using shared_ptr<T>(new T).
Boost documentation states
There have been repeated requests from
users for a factory function that
creates an object of a given type and
returns a shared_ptr to it. Besides
convenience and style, such a function
is also exception safe and
considerably faster because it can use
a single allocation for both the
object and its corresponding control
block, eliminating a significant
portion of shared_ptr's construction
overhead. This eliminates one of the
major efficiency complaints about
shared_ptr.
In addition to the points presented by #deft_code, an even weaker one:
If you use weak_ptrs that live after all the shared_ptrs to a given object have died, then this object's memory will live in memory along with the control block until the last weak_ptr dies. In other words the object is destroyed but not deallocated until the last weak_ptr is destroyed.
I know of at least two.
You must be in control of the allocation. Not a big one really, but some older api's like to return pointers that you must delete.
No custom deleter. I don't know why this isn't supported, but it isn't. That means your shared pointers have to use a vanilla deleter.
Pretty weak points. so try to always use make_shared.
From http://www.codesynthesis.com/~boris/blog/2010/05/24/smart-pointers-in-boost-tr1-cxx-x0/
The other drawback of the make_shared() implementation is the increase in the object code size. Due to the way this optimization is implemented, an additional virtual table as well as a set of virtual functions will be instantiated for each object type that you use with make_shared().
Additionally, make_shared is not compatible with the factory pattern. This is because the call to make_shared within your factory function calls the library code, which in turn calls new, which it doesn't have access to, since it cannot call the class's private constructor(s) (constructor(s) should be private, if you follow the factory pattern correctly).
With make shared you can not specify how allocation and deallocation of the held object will be done.
When that is desired, use std::allocate_shared<T> instead:
std::vector<std::shared_ptr<std::string>> avec;
std::allocator<std::string> aAllocator;
avec.push_back(std::allocate_shared<std::string>(aAllocator,"hi there!"));
Note that the vector does not need to be informed about the allocator!
For making a custom allocator, have a look here https://stackoverflow.com/a/542339/1149664