As illustrated in the code here, the size of the object returned from make_shared is two pointers.
However, why doesn't make_shared work like the following (assume T is the type we're making a shared pointer to):
The result of make_shared is one pointer in size, which points to of allocated memory of size sizeof(int) + sizeof(T), where the int is a reference count, and this gets incremented and decremented on construction/destruction of the pointers.
unique_ptrs are only the size of one pointer, so I'm not sure why shared pointer needs two. As far as I can tell, all it needs a reference count, which with make_shared, can be placed with the object itself.
Also, is there any implementation that is implemented the way I suggest (without having to muck around with intrusive_ptrs for particular objects)? If not, what is the reason why the implementation I suggest is avoided?
In all implementations I'm aware of, shared_ptr stores the owned pointer and the reference count in the same memory block. This is contrary to what other answers are saying. Additionally a copy of the pointer will be stored in the shared_ptr object. N1431 describes the typical memory layout.
It is true that one can build a reference counted pointer with sizeof only one pointer. But std::shared_ptr contains features that absolutely demand a sizeof two pointers. One of those features is this constructor:
template<class Y> shared_ptr(const shared_ptr<Y>& r, T *p) noexcept;
Effects: Constructs a shared_ptr instance that stores p
and shares ownership with r.
Postconditions: get() == p && use_count() == r.use_count()
One pointer in the shared_ptr is going to point to the control block owned by r. This control block is going to contain the owned pointer, which does not have to be p, and typically isn't p. The other pointer in the shared_ptr, the one returned by get(), is going to be p.
This is referred to as aliasing support and was introduced in N2351. You may note that shared_ptr had a sizeof two pointers prior to the introduction of this feature. Prior to the introduction of this feature, one could possibly have implemented shared_ptr with a sizeof one pointer, but no one did because it was impractical. After N2351, it became impossible.
One of the reasons it was impractical prior to N2351 was because of support for:
shared_ptr<B> p(new A);
Here, p.get() returns a B*, and has generally forgotten all about the type A. The only requirement is that A* be convertible to B*. B may derive from A using multiple inheritance. And this implies that the value of the pointer itself may change when converting from A to B and vice-versa. In this example, shared_ptr<B> needs to remember two things:
How to return a B* when get() is called.
How to delete a A* when it is time to do so.
A very nice implementation technique to accomplish this is to store the B* in the shared_ptr object, and the A* within the control block with the reference count.
The reference count cannot be stored in a shared_ptr. shared_ptrs have to share the reference count among the various instances, therefore the shared_ptr must have a pointer to the reference count. Also, shared_ptr (the result of make_shared) does not have to store the reference count in the same allocation that the object was allocated in.
The point of make_shared is to prevent the allocation of two blocks of memory for shared_ptrs. Normally, if you just do shared_ptr<T>(new T()), you have to allocate memory for the reference count in addition to the allocated T. make_shared puts this all in one allocation block, using placement new and delete to create the T. So you only get one memory allocation and one deletion.
But shared_ptr must still have the possibility of storing the reference count in a different block of memory, since using make_shared is not required. Therefore it needs two pointers.
Really though, this shouldn't bother you. Two pointers isn't that much space, even in 64-bit land. You're still getting the important part of intrusive_ptr's functionality (namely, not allocating memory twice).
Your question seems to be "why should make_shared return a shared_ptr instead of some other type?" There are many reasons.
shared_ptr is intended to be a kind of default, catch-all smart pointer. You might use a unique_ptr or scoped_ptr for cases where you're doing something special. Or just for temporary memory allocations at function scope. But shared_ptr is intended to be the sort of thing you use for any serious reference counted work.
Because of that, shared_ptr would be part of an interface. You would have functions that take shared_ptr. You would have functions that return shared_ptr. And so on.
Enter make_shared. Under your idea, this function would return some new kind of object, a make_shared_ptr or whatever. It would have its own equivalent to weak_ptr, a make_weak_ptr. But despite the fact that these two sets of types would share the exact same interface, you could not use them together.
Functions that take a make_shared_ptr could not take a shared_ptr. You might make make_shared_ptr convertible to a shared_ptr, but you couldn't go the other way around. You wouldn't be able to take any shared_ptr and turn it into a make_shared_ptr, because shared_ptr needs to have two pointers. It can't do its job without two pointers.
So now you have two sets of pointers which are half-incompatible. You have one-way conversions; if you have a function that returns a shared_ptr, the user had better be using a shared_ptr instead of a make_shared_ptr.
Doing this for the sake of a pointer's worth of space is simply not worthwhile. Creating this incompatibility, creating two sets of pointers just for 4 bytes? That simply isn't worth the trouble that is caused.
Now, perhaps you would ask, "if you have make_shared_ptr why would you ever need shared_ptr at all?"
Because make_shared_ptr is insufficient. make_shared is not the only way to create a shared_ptr. Maybe I'm working with some C-code. Maybe I'm using SQLite3. sqlite3_open returns a sqlite3*, which is a database connection.
Right now, using the right destructor functor, I can store that sqlite3* in a shared_ptr. That object will be reference counted. I can use weak_ptr where necessary. I can play all the tricks I normally would with a regular C++ shared_ptr that I get from make_shared or whatever other interface. And it would work perfectly.
But if make_shared_ptr exists, then that doesn't work. Because I can't create one of them from that. The sqlite3* has already been allocated; I can't ram it through make_shared, because make_shared constructs an object. It doesn't work with already existing ones.
Oh sure, I could do some hack, where I bundle the sqlite3* in a C++ type who's destructor will destroy it, then use make_shared to create that type. But then using it becomes much more complicated: you have to go through another level of indirection. And you have to go through the trouble of making a type and so forth; the destructor method above at least can use a simple lambda function.
Proliferation of smart pointer types is something to be avoided. You need an immobile one, a movable one, and a copyable shared one. And one more to break circular references from the latter. If you start to have multiple ones of those types, then you either have very special needs or you are doing something wrong.
I have a honey::shared_ptr implementation that automatically optimizes to a size of 1 pointer when intrusive. It's conceptually simple -- types that inherit from SharedObj have an embedded control block, so in that case shared_ptr<DerivedSharedObj> is intrusive and can be optimized. It unifies boost::intrusive_ptr with non-intrusive pointers like std::shared_ptr and std::weak_ptr.
This optimization is only possible because I don't support aliasing (see Howard's answer). The result of make_shared can then have 1 pointer size if T is known to be intrusive at compile-time. But what if T is known to be non-intrusive at compile-time? In this case it's impractical to have 1 pointer size as shared_ptr must behave generically to support control blocks allocated both alongside and separately from their objects. With only 1 pointer the generic behavior would be to point to the control block, so to get at T* you'd have to first dereference the control block which is impractical.
Others have already said that shared_ptr needs two pointers because it has to point to the reference count memory block and the Pointed to Types memory Block.
I guess what you are asking is this:
When using make_shared both memory blocks are merged into one, and because the blocks sizes and alignment are known and fixed at compile time one pointer could be calculated from the other (because they have a fixed offset). So why doesn't the standard or boost create a second type like small_shared_ptr which does only contain one pointer.
Is that about right?
Well the answer is that if you think it through it quickly becomes a large hassle for very little gain. How do you make the pointers compatible? One direction, i.e. assigning a small_shared_ptr to a shared_ptr would be easy, the other way round extremely hard. Even if you solve this problem efficiently, the small efficiency you gain will probably be lost by the to-and-from conversions that will inevitably sprinkle up in any serious program. And the additional pointer type also makes the code that uses it harder to understand.
Related
I wrote a project using normal pointers and now I'm fed up with manual memory management.
What are the issues that one could anticipate during refactoring?
Until now, I already spent an hour replacing X* with shared_ptr<X> for types I want to automatically manage memory. Then I changed dynamic_cast to dynamic_pointer_cast. I still see many more errors (comparing with NULL, passing this to a function).
I know the question is a bit vague and subjective, but I think I can benefit from experience of someone who has already done this.
Are there some pitfalls?
Although it's easy to just use boost::shared_pointer everywhere, you should use the correct smart pointer as per ownership semantics.
In most cases, you will want to use std::unique_ptr by default, unless the ownership is shared among multiple object instances.
If you run into cyclical ownership problems, you can break up the cycles with boost::weak_ptr.
Also keep in mind that while passing shared_ptr's around, you should always pass them by const reference for performance reasons (avoids an atomic increment) unless you really want to confer ownership to a different entity.
Are there some pitfalls?
Yes, by murphy's law if you blindly replace every pointer with shared_ptr, it'll turn out that isn't what you wanted, and you'll spend next 6 months hunting bugs you introduced.
What are the issues that one could anticipate during refactoring?
Inefficient memory management, unused resources being stored longer than necessary, memory leaks (circular references), invalid reference counting (same pointer assigned to multiple different shared_pointers).
Do NOT blindly replace everything with shared_ptr. Carefully investigate program structure and make sure that shread_ptr is NEEDED and it represents EXACTLY what you want.
Also, make sure you use version control that supports easy branching (git or mercurial), so when you break something you can revert to previous state or run something similar to "git bisect" to locate problem.
obviously you need to replace X* with shared_ptr
Wrong. It depends on context. If you have a pointer that points into the middle of some array (say, pixel data manipulation), then you won't be able to replace it with shared_ptr (and you won't need to). You need to use shared_ptr only when you need to ensure automatic deallocation of object. Automatic deallocation of object isn't always what you want.
If you wish to stick with boost, you should consider if you want a boost::shared_ptr or a boost::scoped_ptr. A shared_ptr is a resource to be shared between classes, whereas a scoped_ptr sounds more like what you may want (at least in some places). A scoped_ptr will automatically delete the memory when it goes out of scope.
Be wary when passing a shared_ptr to a function. The general rule with shared_ptr is to pass by value so a copy is created. If you pass it by reference then the pointer's reference count will not be incremented. In this case, you might end up deleting a piece of memory that you wanted kept alive.
There is a case, however, when you might want to pass a shared_ptr by reference. That is, if you want the memory to be allocated inside a different function. In this case, just make sure that the caller still holds the pointer for the lifetime of the function it is calling.
void allocPtr( boost::shared_ptr< int >& ptrByRef )
{
ptrByRef.reset( new int );
*ptrByRef = 3;
}
int main()
{
boost::shared_ptr< int >& myPointer;
// I want a function to alloc the memory for this pointer.
allocPtr( myPointer ); // I must be careful that I still hold the pointer
// when the function terminates
std::cout << *ptrByRef << std::endl;
}
I'm listing the steps/issues involved. They worked for me, but I can't vouch that they are 100% correct
0) check if there could be cyclic shared pointers. If so, can this lead to memory leak? I my case, luckily, cycles need not be broken because if I had a cycle, the objects in the cycle are useful and should not be destroyed. use weak pointers to break cycles
1) you need to replace "most" X* with shared_ptr<X> . A shared_ptr is (only?) created immediately after every dynamic allocation of X . At all other times, it is copy constructed , or constructed with an empty pointer(to signal NULL) . To be safe (but a bit inefficient), pass these shared_ptrs only by reference . Anyways, it's likely that you never passed your pointers by reference to begin with => no additional change is required
2) you might have used dynamic_cast<X*>(y) at some places. replace that with
dynamic_pointer_cast<X>(y)
3) wherever you passed NULL(eg. to signal that a computation failed), pass an empty shared pointer.
4) remove all delete statements for the concerned types
5) make your base class B inherit from enable_shared_from_this<B>. Then wherever you passed this , pass, shared_from_this() . You might have to do static casting if the function expected a derived type . keep in mind that when you call shared_from_this(), some shared_ptr must already be owning this . In particular, don't call shared_from_this() in constructor of the class
I'm sure one could semi-automate this process to get a semantically equivalent but not necessarily very-efficient code. The programmer probably only needs to reason about cyclic reference(if any).
I used regexes a lot in many of these steps. It took about 3-4 hours. The code compiles and has executed correctly so far.
There is a tool that tries to automatically convert to smart pointers. I've never tried it. Here is a quote from the abstract of the following paper:
http://www.cs.rutgers.edu/~santosh.nagarakatte/papers/ironclad-oopsla2013.pdf
To enforce safety properties that are difficult to check statically,
Ironclad C++ applies dynamic checks via templated “smart
pointer” classes.
Using a semi-automatic refactoring tool, we have ported
nearly 50K lines of code to Ironclad C++
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.
class B;
class A
{
public:
A ()
: m_b(new B())
{
}
shared_ptr<B> GimmeB ()
{
return m_b;
}
private:
shared_ptr<B> m_b;
};
Let's say B is a class that semantically should not exist outside of the lifetime of A, i.e., it makes absolutely no sense for B to exist by itself. Should GimmeB return a shared_ptr<B> or a B*?
In general, is it good practice to completely avoid using raw pointers in C++ code, in lieu of smart pointers?
I am of the opinion that shared_ptr should only be used when there is explicit transfer or sharing of ownership, which I think is quite rare outside of cases where a function allocates some memory, populates it with some data, and returns it, and there is understanding between the caller and the callee that the former is now "responsible" for that data.
Your analysis is quite correct, I think. In this situation, I also would return a bare B*, or even a [const] B& if the object is guaranteed to never be null.
Having had some time to peruse smart pointers, I arrived at some guidelines which tell me what to do in many cases:
If you return an object whose lifetime is to be managed by the caller, return std::unique_ptr. The caller can assign it to a std::shared_ptr if it wants.
Returning std::shared_ptr is actually quite rare, and when it makes sense, it is generally obvious: you indicate to the caller that it will prolong the lifetime of the pointed-to object beyond the lifetime of the object which was originally maintaining the resource. Returning shared pointers from factories is no exception: you must do this eg. when you use std::enable_shared_from_this.
You very rarely need std::weak_ptr, except when you want to make sense of the lock method. This has some uses, but they are rare. In your example, if the lifetime of the A object was not deterministic from the caller's point of view, this would have been something to consider.
If you return a reference to an existing object whose lifetime the caller cannot control, then return a bare pointer or a reference. By doing so, you tell the caller that an object exists and that she doesn't have to take care of its lifetime. You should return a reference if you don't make use of the nullptr value.
The question "when should I use shared_ptr and when should I use raw pointers?" has a very simple answer:
Use raw pointers when you do not want to have any ownership attached to the pointer. This job can also often be done with references. Raw pointers can also be used in some low level code (such as for implementing smart pointers, or implementing containers).
Use unique_ptr or scope_ptr when you want unique ownership of the object. This is the most useful option, and should be used in most cases. Unique ownership can also be expressed by simply creating an object directly, rather than using a pointer (this is even better than using a unique_ptr, if it can be done).
Use shared_ptr or intrusive_ptr when you want shared ownership of the pointer. This can be confusing and inefficient, and is often not a good option. Shared ownership can be useful in some complex designs, but should be avoided in general, because it leads to code which is hard to understand.
shared_ptrs perform a totally different task from raw pointers, and neither shared_ptrs nor raw pointers are the best option for the majority of code.
The following is a good rule of thumb:
When there is no transfer of shared ownership references or plain pointers are good enough. (Plain pointers are more flexible than references.)
When there is transfer of ownership but no shared ownership then std::unique_ptr<> is a good choice. Often the case with factory functions.
When there is shared ownership, then it is a good use case for std::shared_ptr<> or boost::intrusive_ptr<>.
It is best to avoid shared ownership, partly because they are most expensive in terms of copying and std::shared_ptr<> takes double of the storage of a plain pointer, but, most importantly, because they are conducive for poor designs where there are no clear owners, which, in turn, leads to a hairball of objects that cannot destroy because they hold shared pointers to each other.
The best design is where clear ownership is established and is hierarchical, so that, ideally, no smart pointers are required at all. For example, if there is a factory that creates unique objects or returns existing ones, it makes sense for the factory to own the objects it creates and just keep them by value in an associative container (such as std::unordered_map), so that it can return plain pointers or references to its users. This factory must have lifetime that starts before its first user and ends after its last user (the hierarchical property), so that users cannot possible have a pointer to an already destroyed object.
If you don't want the callee of GimmeB() to be able to extend the lifetime of the pointer by keeping a copy of the ptr after the instance of A dies, then you definitely should not return a shared_ptr.
If the callee is not supposed to keep the returned pointer for long periods of time, i.e. there's no risk of the instance of A's lifetime expiring before the pointer's, then raw pointer would be better. But even a better choice is simply to use a reference, unless there's a good reason to use an actual raw pointer.
And finally in the case that the returned pointer can exist after the lifetime of the A instance has expired, but you don't want the pointer itself extend the lifetime of the B, then you can return a weak_ptr, which you can use to test whether it still exists.
The bottom line is that there's usually a nicer solution than using a raw pointer.
I agree with your opinion that shared_ptr is best used when explicit sharing of resources occurs, however there are other types of smart pointers available.
In your precise case: why not return a reference ?
A pointer suggests that the data might be null, however here there will always be a B in your A, thus it will never be null. The reference asserts this behavior.
That being said, I have seen people advocating the use of shared_ptr even in non-shared environments, and giving weak_ptr handles, with the idea of "securing" the application and avoiding stale pointers. Unfortunately, since you can recover a shared_ptr from the weak_ptr (and it is the only way to actually manipulate the data), this is still shared ownership even if it was not meant to be.
Note: there is a subtle bug with shared_ptr, a copy of A will share the same B as the original by default, unless you explicitly write a copy constructor and a copy assignment operator. And of course you would not use a raw pointer in A to hold a B, would you :) ?
Of course, another question is whether you actually need to do so. One of the tenets of good design is encapsulation. To achieve encapsulation:
You shall not return handles to your internals (see Law of Demeter).
so perhaps the real answer to your question is that instead of giving away a reference or pointer to B, it should only be modified through A's interface.
Generally, I would avoid using raw pointers as far as possible since they have very ambiguous meaning - you might have to deallocate the pointee, but maybe not, and only human-read and -written documentation tells you what the case is. And documentation is always bad, outdated or misunderstood.
If ownership is an issue, use a smart pointer. If not, I'd use a reference if practicable.
You allocate B at constuction of A.
You say B shouldn't persist outside As lifetime.
Both these point to B being a member of A and a just returning a reference accessor. Are you overengineering this?
I found that the C++ Core Guidelines give some very useful hints for this question:
To use raw pointer(T*) or smarter pointer depends on who owns the object (whose responsibility to release memory of the obj).
own :
smart pointer, owner<T*>
not own:
T*, T&, span<>
owner<>, span<> is defined in Microsoft GSL library
here is the rules of thumb:
1) never use raw pointer(or not own types) to pass ownership
2) smart pointer should only be used when ownership semantics are intended
3) T* or owner designate a individual object(only)
4) use vector/array/span for array
5) To my undetstanding, shared_ptr is usually used when you don't know who will release the obj, for example, one obj is used by multi-thread
It is good practice to avoid using raw pointers, but you can not just replace everything with shared_ptr. In the example, users of your class will assume that it's ok to extend B's lifetime beyond that of A's, and may decide to hold the returned B object for some time for their own reasons. You should return a weak_ptr, or, if B absolutely cannot exist when A is destroyed, a reference to B or simply a raw pointer.
When you say: "Let's say B is a class that semantically should not exist outside of the lifetime of A"
This tells me B should logically not exist without A, but what about physically existing?
If you can be sure no one will try using a *B after A dtors than perhaps a raw pointer will be fine. Otherwise a smarter pointer may be appropriate.
When clients have a direct pointer to A you have to trust they'll handle it appropriately; not try dtoring it etc.
I have a project and I want make smart pointers usage better.
The main idea is to use them when returning new object from function. The question is what smart pointer to use? auto_ptr or shared_ptr from boost? As I know, auto_ptr is slower but it can fall back to the 'pure' pointer.
And if I'll use smart pointer in place where I don't need it, would it make the perfomance slower?
What makes you think auto_ptr is slower than shared_ptr? Typically I would expect the reverse to be true, since shared_ptr needs to update the reference count.
As for which you should use, different smart pointers imply different ownership semantics. Ownership implies the responsibility to delete the object when it is no longer needed.
A raw pointer implies no ownership; a program that uses smart pointers correctly may still make use of raw pointers in a lot of places where ownership is not intended (for example, if you need to pass an optional reference to an object into a function, you would often use a raw pointer).
scoped_ptr implies single (ie, non-shared), non-transferable ownership.
auto_ptr implies single (ie, non-shared) transferable ownership. This is the smart pointer I would use to return a newly constructed object from a function (the function is transferring the object to its caller). auto_ptr suffers from the disadvantage that due to limitations of the language when auto_ptr was defined, it is difficult to use correctly (this has given it a very bad reputation, though the intended purpose of a smart pointer with single, transferable ownership semantics was and is both valid and useful).
unique_ptr has the same semantics as auto_ptr, but uses new C++0x features (rvalue references) to make it a lot safer (less prone to incorrect use) than auto_ptr. If you are developing on a platform where unique_ptr is available, then you should use it instead of auto_ptr.
shared_ptr implies shared ownership. In my opinion this is over-used. It does have many valid uses, but it should not simply be used as a default option.
I would also add that shared_ptr is often used with STL containers because the other smart pointer classes do not achieve their intended function in that context (due to copying of values internally within the container). This often leads to use of shared_ptr where shared ownership is not really the intended meaning. In these cases, I suggest (where possible) using the boost pointer-container classes (ptr_vector, ptr_map and so on), which provide the (commonly desired) semantics of a container with transferable, but single (non-shared) ownership.
You should always think about the ownership of your objects: in most cases, with a clean system design, each object has one obvious owner, and ownership does not need to be shared. This has the advantage that it is easy to see exactly where and when objects will be freed, and no reference counting overhead is needed.
[edited to note the new unique_ptr]
You probably should use shared_ptr<>. It's hard to be more specific without knowing what exactly you want to do. Best read its documentation and see if it does what you need.
The performance difference will most likely be negligible. Only in extreme cases there might me an noticeable impact, like when copying these pointers many million times each second.
I prefer shared_ptr, auto_ptr can cause a lot of trouble and its use is not too intuitive. If you expect this object to be inserted on a STL container, so you certainly want to use shared_ptr.
Abot the performance you have a cost, but this is minimal and you can ignore it most of the time.
Depends.
Shared pointers have a better use than auto_ptr which have the unusual characteristic of changing ownership on assignments.
Also auto_ptr can not be used in containers.
Also you can not use auto_ptr as return values if you do not want to transfer ownership.
Shared pointers have all the benefits of smart pointers, have overloaded the relevant operators to act like a pointer and can be used in containers.
Having said that, they are not cheap to use.
You must analyze your needs to decide if you actually gain something by avoiding the shared_pointer implementation overheads
Use only shared_ptr. With auto_ptr you can have ONLY ONE reference to your object. Also auto_ptr isn't slower it must work faster than shared_ptr.
To not ask such questions you need to know, how this smart pointers work.
auto_ptr just storing pointer to your object and destroying it in it's destructor.
The problem of auto_ptr is that when you are trying to copy it it's stopping to point to your object.
For example
auto_ptr a_ptr(new someClass);
auto_ptr another_ptr=aptr;// after this another_ptr is pointing to your class, but a_ptr isn't pointing to it anymore!
This is why I don't recomend you to use auto_ptr.
Shared pointer counting how much smart pointers are pointing to your object and destroying your object when there is no more pointers to it. That's why you can have more than 1 pointer pointing to your object.
But Shared pointer also isn't perfect. And if in your program you have cyclic graph (when you have classes A and B and A have a member shared_ptr wich points to B and B have or B's member objects have shared_ptr pointing to A) than A and B will never deleted and you will have memory lick.
To write correct code with shared_ptr you need to be careful and also use weak_ptr.
For more information look at here http://www.boost.org/doc/libs/1_45_0/libs/smart_ptr/smart_ptr.htm