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

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

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 (21.51 KB, 5 trang )

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

×