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

O''''Reilly Network For Information About''''s Book part 44 pptx

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

weak_ptr_unary(std::equal_to<string>(),string("of using")));
if (it!=vec.end()) {
shared_ptr<string> sp(*++it);
std::cout << *sp << '\n';
}
}
In the example, a vector containing weak_ptrs is created. The most interesting line
of code (yes, it's quite a long one) is where we create a weak_ptr_unary_t for use
with the find_if algorithm.
vector<weak_ptr<string> >::iterator it=std::find_if(
vec.begin(),
vec.end(),
weak_ptr_unary(
std::equal_to<string>(),string("of using")));
The function object is created by passing another function object, std::equal_to, to
the helper function weak_ptr_unary, together with the string that is to be used for
the matching. Because of the fact that weak_ptr_unary_t is compatible with
adaptors (it is compatible because it inherits from std::unary_function), we could
compose any type of function object out of it. For instance, we could have
searched for the first string not matching "of using":
vector<weak_ptr<string> >::iterator it=std::find_if(
vec.begin(),
vec.end(),
std::not1(
weak_ptr_unary(
std::equal_to<string>(),string("of using"))));
The Boost smart pointers were specifically designed to work well with the
Standard Library. That makes it easy for us to create useful components that help
us simplify the usage of these powerful smart pointers. Utilities such as
weak_ptr_unary aren't needed all that often; there are libraries that provide general
binders that do a much better job of that than weak_ptr_unary.


[15]
These, too, are
typically aware of smart pointer semantics, which makes using them completely
transparent to use.
Two Idiomatic Ways of Creating a shared_ptr from a weak_ptr
As you have seen, when you have a weak_ptr that's observing some resource,
you'll eventually want to access that resource. To do so, the weak_ptr must be
converted to a shared_ptr, because the weak_ptr alone does not allow direct access
to the resource. There are two ways of creating a shared_ptr from a weak_ptr:
Either pass the weak_ptr to the constructor of shared_ptr or call the weak_ptr
member function lock, which returns a shared_ptr. Which to choose depends on
whether you consider an empty weak_ptr to be an error or not. The shared_ptr
constructor accepting a weak_ptr argument will throw an exception of type
bad_weak_ptr if the weak_ptr is empty. It should therefore be used only if an
empty weak_ptr constitutes an error. When using the weak_ptr function lock, the
returned shared_ptr will be empty if the weak_ptr is empty. This is the right thing
to do if you need to test for a valid resourcethat is, an empty weak_ptr is expected
behavior. Furthermore, when using lock
, the idiomatic way to use the resource is to
initialize it and test it simultaneously, like so:
#include <iostream>
#include <string>
#include "boost/shared_ptr.hpp"
#include "boost/weak_ptr.hpp"
int main() {
boost::shared_ptr<std::string>
sp(new std::string("Some resource"));
boost::weak_ptr<std::string> wp(sp);
//
if (boost::shared_ptr<std::string> p=wp.lock())

std::cout << "Got it: " << *p << '\n';
else
std::cout << "Nah, the shared_ptr is empty\n";
}
As you can see, the shared_ptr p is initialized with the result of locking the
weak_ptr wp. Then p is tested, and only if it is non-empty is the resource accessed.
As the shared_ptr is only valid in that scope, there is no chance of inadvertently
trying to use it outside of the scope where it is valid. The other scenario is when
the weak_ptr logically must be non-empty. In that case, testing for an empty
shared_ptr is easy to forgetand because the shared_ptr constructor throws an
exception when handed an empty weak_ptr, this is the way to go.
#include <iostream>
#include <string>
#include "boost/shared_ptr.hpp"
#include "boost/weak_ptr.hpp"
void access_the_resource(boost::weak_ptr<std::string> wp) {
boost::shared_ptr<std::string> sp(wp);
std::cout << *sp << '\n';
}
int main() {
boost::shared_ptr<std::string>
sp(new std::string("Some resource"));
boost::weak_ptr<std::string> wp(sp);
//
access_the_resource(wp);
}
In this example, the function access_the_resource constructs the shared_ptr sp
from a weak_ptr. It doesn't need to test whether the shared_ptr is empty or not,
because if the weak_ptr is empty, an exception of type bad_weak_ptr is thrown,
and therefore the function leaves scope immediately; catching and handling the

error will be handled where it's suitable. This is much better than explicitly testing
for an empty shared_ptr
and then returning. These are the two ways in which to get
a shared_ptr out of a weak_ptr.
Summary

weak_ptr is the last piece that we must place on the Boost smart pointer puzzle.
The weak_ptr abstraction is a very important companion to that of shared_ptr. It
allows us to break cyclic dependencies. It also handles a very common problemthat
of the dangling pointer. When sharing a resource, it is common that some of the
users of that resource must not take part in its lifetime management. This cannot be
handled using raw pointers, because when the last shared_ptr is destroyed, it takes
the shared resource with it. Had raw pointers been used to refer to that resource,
there would be no way of knowing whether the resource still exists. If it doesn't,
accessing it wreaks havoc. With weak_ptrs, the information that the shared
resource has been destroyed is propagated to all weak_ptrs observing it, which
means that no one can inadvertently access an invalid pointer. It's like a special
case of the Observer pattern; when the resource is destroyed, those who have
expressed interest in knowing about it are informed.
Use weak_ptr to
 Break cyclic dependencies
 Use a shared resource without sharing ownership
 Avoid dangling pointers



Smart_ptr Summary
This chapter has introduced the Boost smart pointers, a contribution to the C++
community that can hardly be overestimated. For a smart pointer library to be
successful, it must take into consideration and correctly handle a great number of

factors. I'm sure you have seen quite a number of smart pointers, and you might
have even been involved in their creation, so you are aware of the effort involved
to get things right. Not many smart pointers are as smart as they should be, and that
makes the value of a proven library such as Boost.Smart_ptr immense.
Being such a central component of software engineering, the smart pointers in
Boost have obviously received a lot of attention and thorough review. It is
therefore hard to give credit to all who deserve it. Many have contributed valuable
opinions and have been part of shaping the current smart pointer library. However,
a few exceptional people and efforts must be mentioned here:
 Greg Colvin, the father of auto_ptr, also suggested counted_ptr, which later
became what we now call shared_ptr.

Beman Dawes revived the discussion about smart pointers and proposed that
the original semantics as suggested by Greg Colvin be considered.
 Peter Dimov redesigned the smart pointer classes, adding thread safety,
intrusive_ptr, and weak_ptr.
It is intriguing that such a well-known concept continues to evolve. There will
undoubtedly be more progress in the domain of smart pointers or maybe, smart
resources, but just as important is the quality of smart pointers that are used today.
It's survival of the fittest, and that's why people are using Smart_ptr. The Boost
smart pointers are a fine, assorted selection of delicious software chocolate, and I
eat them regularly (you should, too). We'll soon see some of them become part of
the C++ Standard Library, as they have been accepted into the Library Technical
Report.



Endnotes
15.


Boost.Bind is just such a library.





How Does the Conversion Library Improve Your Programs?
 Understandable, maintainable, and consistent polymorphic conversions
 Static downcasting using safer constructs than static_cast
 Range-preserving numeric conversions that ensure correct value logic and
less time debugging
 Correct and reusable lexical conversions that lead to less time coding
The versatility of C++ is one of the primary reasons for its success, but sometimes
also a formidable source of headaches because of the complexity of certain parts of
the language. For instance, the rules for numeric conversions and type promotions
are far from trivial. Other conversions are trivial, but tedious; how many times do
we need to write a safe function
[1]
for converting between strings and ints, doubles
and strings, and so on? Conversions can be problematic in every library and
program you write, and that's how and why the Conversion library can help. It
provides facilities that prevent dangerous conversions and simplify recurring
conversion tasks.
[1]
To avoid using sprintf and its ilk.
The Conversion library consists of four cast functions that provide better type
safety (polymorphic_cast), better efficiency with preserved type safety
(polymorphic_downcast), range-checked numeric conversions (numeric_cast), and
lexical conversions (lexical_cast). These cast-like functions share the semantics of
the C++ cast operators. Like the C++ cast operators, these functions have an

important quality that, together with type safety, sets them apart from C-
style casts:
They unambiguously state the programmer's intent.
[2]
The importance of the code
we write goes far further than its implementation and present behavior. More
important is to clearly convey our intents when writing it. This library makes it
somewhat easier by extending our C++ vocabulary.
[2]
They can also be overloaded, which sometimes makes them superior to the C++
cast operators.

×