Sign in to follow this  
Genjix

boost smart pointer questions

Recommended Posts

  1. what is the point of a scoped_ptr over pointer/reference? it says non-copyable so isn't that a reference?
  2. intrusive_ptr apparently uses shared ownership of objects with an embedded reference count... isn't this what a shared_ptr does?
basically what is and when am i going to use scoped_ptr and intrusive_ptr? thanks for your time

Share this post


Link to post
Share on other sites
Quote:
Original post by Genjix

  1. what is the point of a scoped_ptr over pointer/reference? it says non-copyable so isn't that a reference?

  2. intrusive_ptr apparently uses shared ownership of objects with an embedded reference count... isn't this what a shared_ptr does?



basically what is and when am i going to use scoped_ptr and intrusive_ptr?

thanks for your time


A scoped pointer just deletes its contents when it goes out of scope. To prevent more than one pointer having control of an object, it must make itself non-copyable.

Compare to a shared pointer that uses reference counting so the object being pointed to is deleted only once but can have several pointers to it (ie: copyable). When the last shared pointer referencing it goes out of scope, it is detected (via reference count) and deleted.

In other words: A scoped pointer dosn't have a reference count - thus it can't do any of the fun copy stuff that shared pointers can.


An intrusive pointer works in the same way as a shared pointer, and it is somewhat faster. However it requires a modification to the object being pointed at (and that may not be possible - say for library objects and basic types). The reason is, instead of storing the reference count as a seperate object, it is stored inside the object being pointed to.


As for when to use them:

Shared Pointer: Whenever you like. Use this as your general-use smart pointer. Use the other for specific cases.

Intrusive Pointer: When you can modify the object and want some more speed.

Scoped Pointer: When you have an object that will only ever have one pointer pointing at it. This is faster than either of the above.

Auto Pointer: Like scoped pointer, but can be copied. Once copied, the original pointer being copied becomes invalid (ownership transfer). This behaviour is somewhat dangerous and weird.

Weak Pointer: If you need to do some kind of circular references that a shared pointer would leak.

Share this post


Link to post
Share on other sites
Quote:
Original post by Genjix
what is the point of a scoped_ptr over pointer/reference? it says non-copyable so isn't that a reference?


No, when you have reference (not pointers) which is already referring to an instance and you preform assignment it does assignment on the original instance it does not change what it refers to.

The point of scoped_ptr/array is to be used in "resource acquisition is initialization" nothing or more less, its simillar to std::auto_ptr but the difference is std::auto_ptr has transfer-of-ownership semantics when scoped_ptr/array does not so scoped_ptr/array is simpler and has a specific purpose.

Quote:
Original post by Genjix
intrusive_ptr apparently uses shared ownership of objects with an embedded reference count... isn't this what a shared_ptr does?


No, shared_ptr/array is non-intrusive, it maintains the reference counting system and can be used with primitive built-types too. intrusive_ptr is exactly that its intrusive, user-defined types maintain the reference counting system thus is slightly more efficent than shared_ptr/array at the cost of being "intrusive".

Quote:
Original post by Genjix
basically what is and when am i going to use scoped_ptr and intrusive_ptr?


Use scoped_ptr/array when you want to use "resource acquisition is initialization" idiom.

You can use intrusive_ptr when you want abit more efficiency than shared_ptr/array but your user-defined type must implement the reference counting system.

Share this post


Link to post
Share on other sites
i didn't realize scoped_ptr's enabled you to use pointers as local objects. thats pretty handy actually (nearly as good as shared_ptr's).

in what way is an intrusive_ptr faster and more efficent? looking through the documentation i can see that intrusive_ptr_add_ref and intrusive_ptr_release should be defined.

why is this more efficent and faster? (no vtable lookups?)

Share this post


Link to post
Share on other sites
Quote:
Original post by Genjix
i didn't realize scoped_ptr's enabled you to use pointers as local objects. thats pretty handy actually (nearly as good as shared_ptr's).

in what way is an intrusive_ptr faster and more efficent? looking through the documentation i can see that intrusive_ptr_add_ref and intrusive_ptr_release should be defined.

why is this more efficent and faster? (no vtable lookups?)


Dosn't have to do with vtables, although the effect is about the same in terms of speed reclaimed - a boost::shared_ptr mantains two pointers IIRC - one to the object, and one to the reference count(s?). The exact mechanism can (or could) vary, but something similar in terms of pointer counts (that is, more than 1) is going to be required. An intrusive pointer only needs to mantain a single pointer for both parts (object data and reference count), which puts the memory closer together (meaning less cache misses when constructing and using pointers) as well as less memory used for an intrusive_ptr.

I havn't used intrusive_ptr myself - the only time I'd use it would be if I had allready been using shared_ptr s and found out that this was prooving to be a bottleneck (with a profiler).

Fortunately it's simple enough that it shouldn't be too hard to add after the fact...

Share this post


Link to post
Share on other sites
ok thanks.

why doesn't intrusive_ptr just define a non-padded structure instead of making you implement methods and reference counts?



// semi-psuedo-code
typedef struct
{
X *object_ptr;
u_int32 refcount;
};


Share this post


Link to post
Share on other sites
Quote:
Original post by Genjix
ok thanks.

why doesn't intrusive_ptr just define a non-padded structure instead of making you implement methods and reference counts?

*** Source Snippet Removed ***


Because you have to mantain a single reference count for the object, not a reference count per pointer :-). Unless I've misunderstood you...?

Anyways, you could do:

struct reference_counted {
mutable unsigned int count;
virtual ~reference_counted( void ) {}
};

void intrusive_ptr_add_ref( const reference_counted * rc ) {
++ rc->count;
}
void intrusive_ptr_release( const reference_counted * rc ) {
if ( ! -- rc->count ) delete rc;
}

class your_class : public reference_counted {
public:
//don't reimplmenet intrusive_ptr stuff
};

boost::intrusive_ptr< your_class > foo( new your_class );


There's also a few more benifits:

1) Assigning multiple intrusive_ptr s to a raw pointer won't cause the pointer to be deleted multiple times
2) You can play together with other reference counting schemes (e.g. the object won't be deleted if any boost::intrusive_ptr s or yourlib::handle s or foo::bar s still reference the object)

Share this post


Link to post
Share on other sites
i mean something like this

template <typename T>
class Reference
{
public:
Reference(T *hard_ptr)
{
object = hard_ptr;
count = 0;
}

T *object;
uint count;
};

template <typename T>
class IntrusivePointer
{
public:
IntrusivePointer(T *hard_ptr)
{
ref = new Reference<T>(hard_ptr);
}
IntrusivePointer(const IntrusivePointer &ptr)
{
operator=(ptr);
}
operator=(const IntrusivePointer &ptr)
{
ref = ptr->ref;
ref->count++;
}

Reference<T> *ref;
};



from what you are saying it seems this is how shared_ptr is implemented and intrusive_ptr simply cuts out the intermediate pointer to pointer redirection by using an inherited interface?

Share this post


Link to post
Share on other sites
Quote:
Original post by MaulingMonkey
1) Assigning multiple intrusive_ptr s to a raw pointer won't cause the pointer to be deleted multiple times


Man! Do you realize you've just answered my previous post with this. It's another way to have an easy "universal" handle system. Just create a handle_base that takes care of the intrusive reference count and that's it. Well, it's another way to do it, I think :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this