shared_ptr custom allocator together with custom deleter - c++

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.

Related

Do I need custom allocators for shared pointers?

If I override operator new and operator delete (or passing a custom deleter), what use is passing an allocator? Will the shared_ptr at some other time than construction and deconstruction do allocations and deallocations?
The allocator passed into a boost::shared_ptr is used to allocate the internal details of the shared pointer (The shared/weak reference counts) and has nothing to do with the object passed in, which you will have already allocated, as you pointed out.
Here is another answer on the subject:
Boost shared_ptr: How to use custom deleters and allocators

Is there any situation in which I wouldn't use std::make_shared?

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.

Some questions about shared_ptr, scoped_ptr and shared_array

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.

Use of deallocator & allocator in shared_ptr

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.

Are there any downsides with using make_shared to create a shared_ptr

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