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

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

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 (33.52 KB, 6 trang )

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.


×