views:

2370

answers:

6

What is the difference between the following set of pointer? When do you use each pointer in a production code, if at all?

Examples would be appreciated!

1.scoped_ptr

2.shared_ptr

3.weak_ptr

4.intrusive_ptr

Edit#1

Do you guys use boost in production code?

+1  A: 

I found a very detailed explanation with code samples for 3 of the pointer types here. I found another site that shows weak_ptr with code examples here.

Both of those seem like excellent, detailed resources.

ryeguy
Thanks, but I find very detailed explanation in the current thread...
+10  A: 

Why not try the boost documentation?

Pesto
I'd imagine that he's looking for something more detailed since he asked this.
ryeguy
Because core documentation is often obscure or written by (and therefore, implicitly, for) language designers rather than language users. A simple explanation or write up by another programmer is often much more useful.
Joel Coehoorn
Right - I'd imagine he's looking for something less detailed. The Boost documentation is generally very good in detail, particularly if you understand the problem domain, but doesn't necessarily give you a feel for the library.
David Thornley
First paragraph of the documentation of each of the pointers seems really clear. It gives short idea and rationale of a given pointer.
Anonymous
The documentation is clear, concise, doesn't assume you know terms like "dynamically allocated" and provides simple examples. If he can't get anything from that, he needs to ask specific questions about the sticking points, not something so general.
Pesto
Don't worry, I gave you an upvote-- the link you gave does point to pretty a good explanation. But even when docs do include a well-written write up of a feature, finding that particular page among all the others often isn't all that easy. RTFM responses often just aren't helpful.
Joel Coehoorn
RTFM responses are only as good as the manuals. In this case, the manual is good. Otherwise I wouldn't have suggested it. My point is that, if as ryeguy says, "he's looking for something more detailed," then he needs to ask something more detailed.
Pesto
I did read the manual! However, I am looking for "how users use the library in practice" as opposed to "how designers want us to use it". And I, by no means, diminish in importance the intended use -- I just want to get a feel from people using it. Thanks
"more detailed" than the official docs? It seems more likely that he's after something less detailed. :)
jalf
Link needs to be updated, it 404s now.
Dennis
+28  A: 

scoped_ptr is the simplest. When it goes out of scope, it is destroyed. The following code is illegal (scoped_ptrs are non-copyable) but will illustrate a point:

std::vector< scoped_ptr<T> > tPtrVec;
{
     scoped_ptr<T> tPtr(new T());
     tPtrVec.push_back(tPtr);
     // raw T* is freed
}
tPtrVec[0]->DoSomething(); // accessing freed memory

shared_ptr is reference counted. Every time a copy or assignment occurs, the reference count is incremented. Every time an instance's destructor is fired, the reference count for the raw T* is decremented. Once it is 0, the pointer is freed.

std::vector< shared_ptr<T> > tPtrVec;
{
     shared_ptr<T> tPtr(new T());
     // This copy to tPtrVec.push_back and ultimately to the vector storage
     // causes the reference count to go from 1->2
     tPtrVec.push_back(tPtr);
     // num references to T goes from 2->1 on the destruction of tPtr
}
tPtrVec[0]->DoSomething(); // raw T* still exists, so this is safe

weak_ptr is a weak-reference to a shared pointer that requires you to check to see if the pointed-to shared_ptr is still around

std::vector< weak_ptr<T> > tPtrVec;
{
     shared_ptr<T> tPtr(new T());
     tPtrVec.push_back(tPtr);
     // num references to T goes from 1->0
}
shared_ptr<T> tPtrAccessed =  tPtrVec[0].lock();
if (tPtrAccessed[0].get() == 0)
{
     cout << "Raw T* was freed, can't access it"
}
else
{
     tPtrVec[0]->DoSomething(); // raw 
}

intrusive_ptr is typically used when there is a 3rd party smart ptr you must use. It will call a free function to add and decrement the reference count.See the link to boost documentation for more info.

Response to Edit

Yes we do.

Doug T.
+3  A: 

I second the advice about looking at the documentation. It is not as scary as it seems. And few short hints:

  • scoped_ptr - a pointer automatically deleted when it goes out of scope. Note - no assignment possible, but introduces no overhead
  • intrusive_ptr - reference counting pointer with no overhead of smart_ptr. However the object itself stores the reference count
  • weak_ptr - works together with shared_ptr to deal with the situations resulting in circular dependencies (read the documentation, and search on google for nice picture ;)
  • shared_ptr - the generic, most powerful (and heavyweight) of the smart pointers (from the ones offered by boost)
  • There is also old auto_ptr, that ensures that the object to which it points gets destroyed automatically when control leaves a scope. However it has different copy semantics than the rest of the guys.
  • unique_ptr - will come with C++0x

Response to edit: Yes

Anonymous
+4  A: 

Don't overlook boost::ptr_container in any survey of boost smart pointers. They can be invaluable in situations where a e.g std::vector<boost::shared_ptr<T> > would be too slow.

timday
+25  A: 

Basic properties of smart pointers

It's easy when you have properties that you can assign each smart pointer. There are two important properties.

  • transfer of ownership
  • share of ownership

The first means that only one smart pointer ever can point to the same object at the same time. If the smart pointer is to be returned from functions, the ownership is transferred to the returned smart pointer, for example.

The second means that multiple smart pointers can point to the same object the same time. This is what applies to a raw pointer to: Two pointers can point to the same object. Thus, this is what one would use by default, if there is no strict need for another kind of smart pointer.

Some smart pointer support neither the first nor the second. They can therefor not be returned from functions or passed somewhere else. Most suitable for RAII purposes where the smart pointer is kept local and is just created so it free's an object after it goes out of scope.

Share of ownership can be implemented by having a copy constructor. This naturally copies a smart pointer and both the copy and the original will reference the same object. Transfer of ownership can not be really implemented in C++ currently, because there is no means to transfer something from one object to another supported by the language: If you try to return an object from a function, what is happening is that the object is copied. So a smart pointer that implements transfer of ownership has to use the copy constructor to implement that transfer of ownership. However, this in turn breaks its usage in containers, because requirements state a certain behavior of the copy constructor of elements of containers which is incompatible with this so-called "moving constructor" behavior of these smart pointers.

C++1x provides native support for transfer-of-ownership by introducing so-called "move constructors" and "move assignment operators". It also comes with such a transfer-of-ownership smart pointer called unique_ptr.

Categorizing smart pointers

scoped_ptr is a smart pointer that is neither transferable nor sharable. It's just usable if you locally need to allocate memory, but be sure it's freed again when it goes out of scope. But it can still be swapped with another scoped_ptr, if you wish to do so.

shared_ptr is a smart pointer that shares ownership (second kind above). It is reference counted so it can see when the last copy of it goes out of scope and then it frees the object managed.

weak_ptr is not really a smart pointer itself, but it is used to reference a manged object (managed by a shared_ptr) without adding a reference count. Normally, you would need to get the raw pointer out of the shared_ptr and copy that around. But that would not be safe, as you would not have a way to check when the object was actually deleted. So, weak_ptr provides a mean by referencing an object managed by shared_ptr. If you need to access the object, you can lock the management of it (to avoid that in another thread a shared_ptr frees it while you use the object) and then use it. If the weak_ptr points to an object already deleted, it will notice you by throwing an exception. Using weak_ptr is most beneficial when you have a cyclic reference: Reference counting cannot easily cope with such a situation.

intrusive_ptr is like a shared_ptr but it does not keep the reference count in a shared_ptr but leaves incrementing/decrementing the count to some helper functions that need to be defined by the object that is managed. This has the advantage that an already referenced object (which has a reference count incremented by an external reference counting mechanism) can be stuffed into an intrusive_ptr - because the reference count is not anymore internal to the smart pointer, but the smart pointer uses an existing reference counting mechanism. Often this will also provide a speed enhancement, because the reference count can be stored in the managed object itself (thus the name intrusive) which provides better cache locality.

unique_ptr is a transfer of ownership pointer. You cannot copy it, but you can move it by using C++1x's move constructors:

unique_ptr<type> p(new type);
unique_ptr<type> q(p); // not legal!
unique_ptr<type> r(move(p)); // legal. p is now empty, but r owns the object
unique_ptr<type> s(function_returning_a_uique_ptr()); // legal!

This is the semantic that std::auto_ptr obeys, but because of missing native support for moving, it fails to provide them without pitfalls. unique_ptr will automatically steal resources from a temporary other unique_ptr which is one of the key features of move semantics. auto_ptr will be deprecated in the next C++ Standard release in favor of unique_ptr. C++1x will also allow stuffing objects that are only movable but not copyable into containers. So you can stuff unique_ptr's into a vector for example. I'll stop here and reference you to a fine article about this if you want to read more about this.

Johannes Schaub - litb
very educational, a great read. +1.
Doug T.
thanks for the praise dude. i appreciate it so you're going to get +1 now too :p
Johannes Schaub - litb
legends2k