1. Trang chủ
  2. » Công Nghệ Thông Tin

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

5 58 0

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 5
Dung lượng 21,79 KB

Nội dung

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 { . 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. 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

Ngày đăng: 06/07/2014, 04:20