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

HandBooks Professional Java-C-Scrip-SQL part 39 pdf

5 76 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,51 KB

Nội dung

never throws. T* operator->() const; The operator returns the stored pointer. This, together with operator* is what makes the smart pointer look like an ordinary pointer. This operator never throws. T* get() const; The get function is the preferred way of retrieving the stored pointer when it might be null (in which case operator* and operator-> leads to undefined behavior). Note that it is also possible to test whether a shared_ptr contains a valid pointer by using the implicit Boolean conversion. This function never throws. bool unique() const; This function returns true if the shared_ptr is the sole owner of the stored pointer; otherwise, it returns false. unique never throws. long use_count() const; The use_count function returns the reference count for the pointer. It is especially useful for debugging purposes, because it can be used to get snapshots of the reference count at critical points of program execution. Use it sparingly. For some possible implementations of the shared_ptr interface, calculating the reference count may be expensive or even impossible. The function never throws. operator unspecified-bool-type() const; This implicit conversion to a type, unspecified-bool-type, makes it possible to test a smart pointer in Boolean contexts. The value is TRue if the shared_ptr is currently storing a valid pointer; otherwise, it is false. Note that the type that this conversion function returns is not specified. Using bool as the return type allows for some nonsensical operations, so typically, an implementation uses the safe bool idiom, [8] which is a nifty way of ensuring that only applicable Boolean tests can be used. The function never throws. [8] Invented by Peter Dimov. void swap(shared_ptr<T>& b); It is sometimes convenient to swap the contents of two shared_ptrs. The swap function exchanges the stored pointers (and their reference counts). This function never throws. Free Functions template <typename T,typename U> shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r); To perform a static_cast on a pointer stored in a shared_ptr, we could retrieve the pointer and then cast it, but we couldn't store it in another shared_ptr; the new shared_ptr would think it was the first to manage the resource the pointer refers to. This is remedied by static_pointer_cast. Using this function ensures that the reference count for the pointee remains correct. static_pointer_cast never throws exceptions. Usage The primary problem solved by shared_ptr is knowing the correct time to delete a resource that is shared by more than one client. Here's a straightforward example, where two classes, A and B, are sharing an instance of int. To start using boost::shared_ptr, you need to include "boost/shared_ptr.hpp". #include "boost/shared_ptr.hpp" #include <cassert> class A { boost::shared_ptr<int> no_; public: A(boost::shared_ptr<int> no) : no_(no) {} void value(int i) { *no_=i; } }; class B { boost::shared_ptr<int> no_; public: B(boost::shared_ptr<int> no) : no_(no) {} int value() const { return *no_; } }; int main() { boost::shared_ptr<int> temp(new int(14)); A a(temp); B b(temp); a.value(28); assert(b.value()==28); } The classes A and B both store a shared_ptr<int>. When creating the instances of A and B, the shared_ptr temp is passed to their constructors. This means that all three shared_ptrsa, b, and tempare now referring to the same instance of an int. Had we used pointers to achieve such sharing of an int, A and B would have had a hard time figuring out when (and if!) it should be deleted. In the example, the reference count is 3 until the end of main, where all of the shared_ptrs go out of scope, decreasing the count until it reaches 0, allowing the last of the smart pointers to delete the shared int. The Pimpl Idiom Revisited The pimpl idiom was previously presented in conjunction with scoped_ptr, which works well as a means of storing the dynamically allocated instance of the pimpl, if copying is not permitted for the class using the idiom. That is not appropriate for all classes that would benefit from using the pimpl idiom (note that scoped_ptr can still be used, but copy construction and assignment need to be implemented by hand). For those classes that can handle shared implementation details, shared_ptr comes into play. When ownership of the pimpl is passed to a shared_ptr, the copying and assignment operators come for free. You'll recall that when using scoped_ptr to handle the lifetime of the pimpl class, copying of the outer class is not allowed, because scoped_ptrs are not copyable. This means that to support copying and assignment in such classes, a copy constructor and assignment operator must be defined manually. When using shared_ptr to handle the lifetime of the pimpl, a user-defined copy constructor may not even be needed. Note that the pimpl instance will be shared among the objects of the class, so if there is state that only applies to one instance of the class, a handcrafted copy constructor is still required. The solution is very similar to what we saw for scoped_ptr; just make it a shared_ptr, instead. shared_ptr and Standard Library Containers Storing objects directly in a container is sometimes troublesome. Storing objects by value means clients get copies of the container elements, which may be a performance problem for types where copying is an expensive operation. Furthermore, some containers, notably std::vector, copy elements when resizing as you add more elements, further adding to the performance problems. Finally, value semantics means no polymorphic behavior. If you need to store polymorphic objects in a container and you don't want to slice them, you must use pointers. If you use raw pointers, the complexity of maintaining the integrity of the elements skyrockets. That is, you must know whether clients of the container still refer to elements of the container when erasing them from the container, never mind coordinating multiple clients using the same element. Such problems are solved handily by shared_ptr. The following example shows how to store shared pointers in a Standard Library container. #include "boost/shared_ptr.hpp" #include <vector> #include <iostream> class A { public: virtual void sing()=0; protected: virtual ~A() {}; }; class B : public A { public: virtual void sing() { std::cout << "Do re mi fa so la"; } }; boost::shared_ptr<A> createA() { boost::shared_ptr<A> p(new B()); return p; } int main() { typedef std::vector<boost::shared_ptr<A> > container_type; typedef container_type::iterator iterator; container_type container; for (int i=0;i<10;++i) { container.push_back(createA()); } std::cout << "The choir is gathered: \n"; iterator end=container.end(); for (iterator it=container.begin();it!=end;++it) { (*it)->sing(); } } The two classes, A and B, contain a single virtual member function sing. B derives publicly from A, and as you can see, the factory function createA returns a dynamically allocated instance of B wrapped in a shared_ptr<A>. In main, a std::vector containing shared_ptr<A> is filled with 10 elements, and finally sing is invoked on each element. Had we been using raw pointers as elements, the objects would need to be manually deleted. In the example, this deletion is automatic, because the reference count of each shared_ptr in the container is 1 as long as the vector is kept alive; when the vector is destroyed, the reference counters all go down to zero, and the objects are deleted. It is interesting to note that even if the destructor of A had not been declared virtual, shared_ptr would have correctly invoked the destructor of B! A powerful technique is demonstrated in the example, and it involves the protected destructor in A. Because the function createA returns a shared_ptr<A>, it won't be possible to invoke delete on the pointer returned by shared_ptr:: get. This means that if the pointer in the shared_ptr is retrievedperhaps in order to pass it to a function expecting a raw pointerit won't be possible to accidentally delete it, which would wreak havoc. So, how is it that the shared_ptr is allowed to delete the object? It's because of the actual type of the pointer, which is B; B's destructor is not protected. This is a very useful way of adding extra safety to objects kept in shared_ptrs. shared_ptr and Other Resources Sometimes, you'll find yourself in need for using shared_ptr with a type that

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