Tải bản đầy đủ (.pdf) (5 trang)

HandBooks Professional Java-C-Scrip-SQL part 41 ppt

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (21.79 KB, 5 trang )

intrusive_ptr
Header: "boost/intrusive_ptr.hpp"
intrusive_ptr is the intrusive analogue to shared_ptr. Sometimes, there's no other
choice than using an intrusive, reference-counted smart pointer. The typical
scenario is for code that has already been written with an internal reference
counter, and where there's no time to rewrite it (or where the code's not available).
Another case is when the size of a smart pointer must be exactly the size of a raw
pointer, or when performance is hurt by the allocation of the reference count for
shared_ptr (a rare case, I'm sure!). The only case where it would seem that an
intrusive smart pointer is required, from a functional perspective, is when a
member function of a pointed-to class needs to return this, such that it can be used
in another smart pointer. (Actually, there are ways to solve that problem with non-
intrusive smart pointers too, as we saw earlier in this chapter.) intrusive_ptr is
different from the other smart pointers because it requires you to provide the
reference counter that it manipulates.
When intrusive_ptr increments or decrements a reference count on a non-null
pointer, it does so by making unqualified calls to the functions
intrusive_ptr_add_ref and intrusive_ptr_release, respectively. These functions are
responsible for making sure that the reference count is always correct and, if the
reference counter drops to zero, to delete the pointer. Therefore, you must overload
those functions for your type, as we shall see later.
This is a partial synopsis for intrusive_ptr, showing the most important functions.
namespace boost {
template<class T> class intrusive_ptr {
public:
intrusive_ptr(T* p,bool add_ref=true);
intrusive_ptr(const intrusive_ptr& r);
~intrusive_ptr();
T& operator*() const;
T* operator->() const;
T* get() const;


operator unspecified-bool-type() const;
};
template <class T> T* get_pointer(const intrusive_ptr<T>& p);
template <class T,class U> intrusive_ptr<T>
static_pointer_cast(const intrusive_ptr<U>& r);
}
Members
intrusive_ptr(T* p,bool add_ref=true);
This constructor stores the pointer p in *this. If p isn't null, and if add_ref is true,
the constructor makes an unqualified call to intrusive_ptr_add_ref(p). If add_ref is
false, the constructor makes no call to intrusive_ptr_add_ref. This constructor can
throw an exception if intrusive_ptr_add_ref can throw.
intrusive_ptr(const intrusive_ptr& r);
The copy constructor saves a copy of r.get() and, if that pointer is not null, calls
intrusive_ptr_add_ref with it. This constructor never throws.
~intrusive_ptr();
If the stored pointer is not null, the intrusive_ptr destructor makes an unqualified
call to the function intrusive_ptr_release, with the stored pointer as argument.
intrusive_ptr_release is responsible for decrementing the reference count and
deleting the pointer if it becomes zero. This function never throws.
T& operator*() const;
This dereferencing operator returns and dereferences the stored pointer. If the
stored pointer is null, invoking this operator results in undefined behavior. When in
doubt, make sure that the intrusive_ptr has a non-null pointer. This is done using
either the function get or by testing the intrusive_ptr in a Boolean context. The
dereferencing operator never throws.
T* operator->() const;
This operator returns the stored pointer. Calling this operator when the referenced
pointer is null invokes undefined behavior. The operator never throws.
T* get() const;

This member function returns the stored pointer. It can be used when a raw pointer
is needed, and may be called even when the stored pointer is null. This function
never throws.
operator unspecified-bool-type() const;
This conversion function returns a type that can be used in Boolean expressions,
but it is not operator bool, because that would allow for other operations that
should be prohibited. The conversion allows intrusive_ptr to be tested in Boolean
contextsfor example, if (p), with p being an instance of intrusive_ptr. The returned
value is TRue if the intrusive_ptr references a non-null pointer; otherwise, it
returns false. This conversion function never throws.
Free Functions
template <class T> T* get_pointer(const intrusive_ptr<T>& p);
The function returns p.get(), and its purpose is mainly to support generic
programming.
[10]
It may also be used as a coding convention instead of calling the
member function get, because it can be overloaded to work with raw pointers and
third-party smart pointer classes. Some simply prefer calling a free function over
accessing a member function.
[11]
The function never throws.
[10]
Such functions are known as shims. See [12] in the Bibliography.
[11]
The idea is that the line between operating on the smart pointer and operating
on what it points to can be blurred when using smart pointer member functions.
For example, p.get() and p->get() have completely different meanings and can be a
little difficult to distinguish at a glance, whereas get_pointer(p) and p->get() look
nothing alike. Whether that's a problem for you is a matter of taste and experience.
template <class T,class U>

intrusive_ptr<T> static_pointer_cast(const intrusive_ptr<U>& r);
This function returns intrusive_ptr<T>(static_cast<T*>(r.get())). Unlike with
shared_ptr, you can use static_cast safely on pointers to objects stored in
intrusive_ptrs. However, you may want to use this function for consistent usage of
smart pointer casts. static_pointer_cast never throws.
Usage
There are two major differences when using intrusive_ptr compared to using
shared_ptr. The first is that you need to provide the reference counting mechanism.
The second is that it becomes legal to treat this as a smart pointer,
[12]
which can
sometimes be convenient, as we shall see. Note that in most cases, the right smart
pointer to use is the non-intrusive shared_ptr.
[12]
You cannot do that with shared_ptr without special measures, such as
enable_shared_from_this.
To use boost::intrusive_ptr, include "boost/intrusive_ptr.hpp" and then define the
two free functions intrusive_ptr_add_ref and intrusive_ptr_release. These should
accept an argument that is a pointer to the type(s) that you want to use with
intrusive_ptr. Any return value from these two functions is discarded. Often, it
makes sense to parameterize these functions, and simply forward to member
functions of the managed type to do the work (for example, calling add_ref and
release). If the reference counter becomes zero, intrusive_ptr_release should take
care of releasing the resource. Here's how you might implement these functions
generically:
template <typename T> void intrusive_ptr_add_ref(T* t) {
t->add_ref();
}
template <typename T> void intrusive_ptr_release(T* t) {
if (t->release()<=0)

delete t;
}
Note that these functions should be defined in the scope of their argument types.
This means that if this function is called with arguments from a namespace, the
functions should be defined there, too. The reason for this is that the calls are
unqualified, which means that argument-dependent lookup is permitted, and there
may be cases where more than one version of these functions must be provided,
which makes the global namespace a bad place to put them. We'll see an example
of where to place these functions later, but first, we need to provide some sort of
internal reference counter.
Providing a Reference Counter
Now that the management functions have been defined, we must provide an
internal reference count. In this example, the reference count is a private data
member that's initialized to zero, and we'll expose add_ref and release member
functions to manipulate it. add_ref increments the reference count and release
decrements it.
[13]
We could add a third member function to return the current value
of the reference count, but it suffices to have release return it. The following base
class, reference_counter, provides a counter and the add_ref and release member
functions, making adding reference counting to a class as easy as using inheritance.
[13]
Note that in a multithreaded environment, any operation on the variable holding
the reference count needs to be synchronized.
class reference_counter {
int ref_count_;
public:
reference_counter() : ref_count_(0) {}

virtual ~reference_counter() {}

void add_ref() {
++ref_count_;
}
int release() {
return ref_count_;
}
protected:
reference_counter& operator=(const reference_counter&) {
// No-op
return *this;
}
private:
// Copy construction disallowed
reference_counter(const reference_counter&);
};
The reason for making the destructor of reference_counter virtual is that the class
is publicly inherited, and thus it is possible to delete derived classes using a pointer
to reference_counter. We want this deletion to do the right thingthat is, to call the
destructor for the derived type. The implementation is straightforward: add_ref
increments the reference count and release decrements the current reference count
and returns it. To use this reference counter, all that's needed is to derive publicly
from it. Here's an example with a class some_ class that contains an internal
reference count, and intrusive_ptrs that use it.
#include <iostream>
#include "boost/intrusive_ptr.hpp"
class some_class : public reference_counter {

×