O''''Reilly Network For Information About''''s Book part 40 docx

6 261 0
O''''Reilly Network For Information About''''s Book part 40 docx

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

Thông tin tài liệu

requires other cleanup than a simple delete. There is support for such cases in shared_ptr tHRough what is called custom deleters. Resource handles, such as FILE*, or operating systemspecific handles, are typically released through an operation such as fclose. To use a FILE* in a shared_ptr , we define a class that is responsible for deallocating the resource. class FileCloser { public: void operator()(FILE* file) { std::cout << "The FileCloser has been called with a FILE*, " "which will now be closed.\n"; if (file!=0) fclose(file); } }; This is the function object that we'll use to make sure that fclose is called when the resource should be released. Here's an example program that utilizes our FileCloser class. int main() { std::cout << "shared_ptr example with a custom deallocator.\n"; { FILE* f=fopen("test.txt","r"); if (f==0) { std::cout << "Unable to open file\n"; throw "Unable to open file"; } boost::shared_ptr<FILE> my_shared_file(f, FileCloser()); // Position the file pointer fseek(my_shared_file.get(),42,SEEK_SET); } std::cout << "By now, the FILE has been closed!\n"; } Note that to get the resource, we need to use the unpronounceable &* idiom, get, or get_pointer on the shared_ptr. (I clearly caution against using &*. The choice between the other two is less clear.) The example could be made even simplerif we don't need to do more than call a single argument function when deallocating, there's really no need to create a custom deleter class at all. The example could be rewritten as follows: { FILE* f=fopen("test.txt","r"); if (f==0) { std::cout << "Unable to open file\n"; throw file_exception(); } boost::shared_ptr<FILE> my_shared_file(f,&fclose); // Position the file pointer fseek(&*my_shared_file,42,SEEK_SET); } std::cout << "By now, the FILE* has been closed!\n"; Custom deleters are extremely useful for handling resources that need a special release procedure. Because the deleter is not part of the shared_ptr type, clients need not know anything about the resource that the smart pointer owns (besides how to use it, of course!). For example, a pool of objects can be used, and the custom deleter would simply return the object to the pool. Or, a singleton object could have a deleter that does nothing. Security Through Custom Deleters We've already seen how using a protected destructor in a base class helps add safety to classes used with shared_ptr. Another way of achieving the same level of safety is to declare the destructor protected (or private) and use a custom deleter to take care of destroying the object. This custom deleter must be made a friend of the class that it is to delete for this to work. A nice way to encapsulate this deleter is to implement it as a private nested class, like the following example demonstrates: #include "boost/shared_ptr.hpp" #include <iostream> class A { class deleter { public: void operator()(A* p) { delete p; } }; friend class deleter; public: virtual void sing() { std::cout << "Lalalalalalalalalalala"; } static boost::shared_ptr<A> createA() { boost::shared_ptr<A> p(new A(),A::deleter()); return p; } protected: virtual ~A() {}; }; int main() { boost::shared_ptr<A> p=A::createA(); } Note that we cannot use a free function as a factory for shared_ptr<A> here, because the nested deleter class is private to A. Using this scheme, it isn't possible for users to create As on the stack, and it isn't possible to call delete using a pointer to A. Creating a shared_ptr from this Sometimes, it is necessary to obtain a shared_ptr from thisthat is, you are making the assumption that your class is being managed by a shared_ptr, and you need a way to convert "yourself" into that shared_ptr. Sounds like a mission impossible? Well, the solution comes from a smart pointer component that we've yet to discussboost::weak_ptr. A weak_ptr is an observer of shared_ptrs; it just silently sits and watches them, but does not affect the reference count. By storing a weak_ptr to this as a member of the class, it's possible to retrieve a shared_ptr to this on demand. To relieve you from the tedium of having to write the code for storing a weak_ptr to this and subsequently obtain a shared_ptr from that weak_ptr, Boost.Smart_ptr provides a helper class for this task, called enable_shared_from_this. Simply have your class derive publicly from enable_shared_from_this, and then use the function shared_from_this whenever you need to access the shared_ptr that is managing this. Here's an example that demonstrates how enable_shared_from_this is used: #include "boost/shared_ptr.hpp" #include "boost/enable_shared_from_this.hpp" class A; void do_stuff(boost::shared_ptr<A> p) { } class A : public boost::enable_shared_from_this<A> { public: void call_do_stuff() { do_stuff(shared_from_this()); } }; int main() { boost::shared_ptr<A> p(new A()); p->call_do_stuff(); } The example also demonstrates a case where you need the shared_ptr that is managing this. Class A has a member function call_do_stuff that needs to call the free function do_stuff, which expects an argument of type boost:: shared_ptr<A>. Now, in A::call_do_stuff, this is simply a pointer to A , but because A derives from enable_shared_from_this, calling shared_from_this returns the shared_ptr that we're seeking. In shared_from_this, which is a member of enable_shared_from_this, the internally stored weak_ptr is converted to a shared_ptr, thereby increasing the reference count to make sure that the object is not deleted. Summary Reference-counted smart pointers are extremely important tools. Boost's shared_ptr provides a solid and flexible solution that is proven through extensive use in many environments and circumstances. It is common to need to share objects among clients, and that often means that there is no way of telling if, and when, the object can be deleted safely. shared_ptr insulates clients from knowing about what other objects are using a shared object, and relieves them of the task of releasing the resource when no objects refer to it. This is arguably the most important of the smart pointer classes in Boost. You should get acquainted with the other classes in Boost.Smart_ptr, too, but this one should definitely be kept close to heart. By using custom deleters, almost any type of resource can be stored in shared_ptrs. This makes shared_ptr a general class for handling resource management, rather than "just" handling dynamically allocated objects. There is a small overhead in size for shared_ptr compared to a raw pointer. I have yet to see a case where this overhead actually matters so much that another solution must be sought. Don't roll your own reference- counted smart pointer class. Instead, use shared_ptrsmart pointers don't get much better than this. Use shared_ptr in the following scenarios:  When there are multiple clients of an object, but no explicit owner  When storing pointers in Standard Library containers  When passing objects to and from libraries without (other) expressed ownership  When managing resources that need special cleanup [9] [9] With the help of custom deleters. shared_array Header: "boost/shared_array.hpp" shared_array is a smart pointer that enables shared ownership of arrays. It is to shared_ptr what scoped_array is to scoped_ptr. shared_array differs from shared_ptr mainly in that it is used with arrays rather than a single object. When we discussed scoped_array, I mentioned that std::vector was often a better choice. But shared_array adds some value over vector, because it offers shared ownership of arrays. The shared_array interface is similar to that of shared_ptr, but with the addition of a subscript operator and without support for custom deleters. Because a shared_ptr to std::vector offers much more flexibility than shared_array, there's no usage section on shared_array in this chapter. If you find that you need boost::shared_array, refer to the online documentation. . closed! "; Custom deleters are extremely useful for handling resources that need a special release procedure. Because the deleter is not part of the shared_ptr type, clients need not know. use a free function as a factory for shared_ptr<A> here, because the nested deleter class is private to A. Using this scheme, it isn't possible for users to create As on the stack,. tedium of having to write the code for storing a weak_ptr to this and subsequently obtain a shared_ptr from that weak_ptr, Boost.Smart_ptr provides a helper class for this task, called enable_shared_from_this.

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

Tài liệu cùng người dùng

Tài liệu liên quan