From 024f918b867168d42a0cf041b2fd5dbe17c0e870 Mon Sep 17 00:00:00 2001
From: Peter Dimov The scoped_ptr class template stores a pointer to a dynamically allocated
-object. (Dynamically allocated objects are allocated with the C++ new
-expression.) The object pointed to is guaranteed to be deleted,
-either on destruction of the scoped_ptr, or via an explicit reset.
-See the example. The scoped_ptr template is a simple solution for simple
-needs. It supplies a basic "resource acquisition is
-initialization" facility, without shared-ownership or transfer-of-ownership
-semantics. Both its name and enforcement of semantics (by being
-noncopyable)
-signal its intent to retain ownership solely within the current scope.
-Because it is noncopyable, it is
-safer than shared_ptr or std::auto_ptr for pointers which should not be
-copied. Because scoped_ptr is simple, in its usual implementation
-every operation is as fast as for a built-in pointer and it has no more space overhead
-that a built-in pointer. It cannot be used in C++ Standard Library containers.
-See shared_ptr
-or std::auto_ptr if scoped_ptr does not meet your needs. It cannot correctly hold a pointer to a
-dynamically allocated array. See scoped_array
-for that usage. The class template is parameterized on T, the type of the object
-pointed to. T must meet the smart pointer
-common requirements. The scoped_ptr class template stores a pointer to a dynamically allocated
+ object. (Dynamically allocated objects are allocated with the C++ new expression.)
+ The object pointed to is guaranteed to be deleted, either on destruction of the scoped_ptr,
+ or via an explicit reset. See the example. The scoped_ptr template is a simple solution for simple needs. It
+ supplies a basic "resource acquisition is initialization" facility, without
+ shared-ownership or transfer-of-ownership semantics. Both its name and
+ enforcement of semantics (by being
+ noncopyable) signal its intent to retain ownership solely within the
+ current scope. Because it is noncopyable,
+ it is safer than shared_ptr or std::auto_ptr for pointers which
+ should not be copied. Because scoped_ptr is simple, in its usual implementation every operation
+ is as fast as for a built-in pointer and it has no more space overhead that a
+ built-in pointer. scoped_ptr cannot be used in C++ Standard Library
+ containers. Use shared_ptr if you need
+ a smart pointer that can. scoped_ptr cannot correctly hold a pointer to a dynamically
+ allocated array. See scoped_array for
+ that usage. The class template is parameterized on T, the type of the object pointed
+ to. T must meet the smart pointer
+ common requirements. Provides the type of the stored pointer. Constructs a scoped_ptr, storing a copy of p, which must
-have been allocated via a C++ new expression or be 0.
-T is not required be a complete type.
-See the smart pointer
-common requirements. Deletes the object pointed to by the stored pointer.
-Note that delete on a pointer with a value of 0 is harmless.
-The guarantee that this does not throw exceptions depends on the requirement that the
-deleted object's destructor does not throw exceptions.
-See the smart pointer common requirements. If p is not equal to the stored pointer, deletes the object pointed to by the
-stored pointer and then stores a copy of p, which must have been allocated via a
-C++ new expression or be 0.
-The guarantee that this does not throw exceptions depends on the requirement that the
-deleted object's destructor does not throw exceptions.
-See the smart pointer common requirements. Returns a reference to the object pointed to by the stored pointer.
-Behavior is undefined if the stored pointer is 0. Returns the stored pointer. Behavior is undefined if the stored pointer is 0. Returns the stored pointer.
-T need not be a complete type.
-See the smart pointer
-common requirements. Exchanges the contents of the two smart pointers.
-T need not be a complete type.
-See the smart pointer
-common requirements. Equivalent to a.swap(b). Matches the interface of std::swap.
-Provided as an aid to generic programming. Here's an example that uses scoped_ptr. Provides the type of the stored pointer. Constructs a scoped_ptr, storing a copy of p, which must have been
+ allocated via a C++ new expression or be 0. T is not required be
+ a complete type. See the smart pointer common
+ requirements. Destroys the object pointed to by the stored pointer, if any, as if by using delete
+ this->get().
+ The guarantee that this does not throw exceptions depends on the requirement
+ that the deleted object's destructor does not throw exceptions. See the smart
+ pointer common requirements. If p is not equal to the stored pointer, deletes the object pointed to by the
+ stored pointer and then stores a copy of p, which must have been allocated via
+ a C++ new expression or be 0. The guarantee that this does not throw
+ exceptions depends on the requirement that the deleted object's destructor does
+ not throw exceptions. See the smart pointer
+ common requirements. Returns a reference to the object pointed to by the stored pointer. Behavior is
+ undefined if the stored pointer is 0. Returns the stored pointer. Behavior is undefined if the stored pointer is 0. Returns the stored pointer. T need not be a complete type. See the smart
+ pointer common requirements. Exchanges the contents of the two smart pointers. T need not be a
+ complete type. See the smart pointer common
+ requirements. Equivalent to a.swap(b). Matches the interface of std::swap.
+ Provided as an aid to generic programming. Here's an example that uses scoped_ptr. The example program produces the beginning of a child's nursery rhyme: The example program produces the beginning of a child's nursery rhyme: The primary reason to use scoped_ptr rather than auto_ptr is to let readers
-of your code know that you intend "resource acquisition is initialization" to be applied only
-for the current scope, and have no intent to transfer ownership. A secondary reason to use scoped_ptr is to prevent a later maintenance programmer
-from adding a function that transfers ownership by returning the auto_ptr,
-because the maintenance programmer saw auto_ptr, and assumed ownership could safely
-be transferred. Think of bool vs int. We all know that under the covers bool is usually
-just an int. Indeed, some argued against including bool in the
-C++ standard because of that. But by coding bool rather than int, you tell your readers
-what your intent is. Same with scoped_ptr; by using it you are signaling intent. It has been suggested that scoped_ptr<T> is equivalent to
-std::auto_ptr<T> const. Ed Brey pointed out, however, that
-reset will not work on a std::auto_ptr<T> const. One common usage of scoped_ptr is to implement a handle/body (also
-called pimpl) idiom which avoids exposing the body (implementation) in the header
-file. The scoped_ptr_example_test.cpp
-sample program includes a header file, scoped_ptr_example.hpp,
-which uses a scoped_ptr<> to an incomplete type to hide the
-implementation. The
-instantiation of member functions which require a complete type occurs in
-the scoped_ptr_example.cpp
-implementation file. Q. Why doesn't scoped_ptr have a release() member? Revised 1 February 2002 Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler.
-Permission to copy, use, modify, sell and distribute this document is granted
-provided this copyright notice appears in all copies.
-This document is provided "as is" without express or implied warranty,
-and with no claim as to its suitability for any purpose. The primary reason to use scoped_ptr rather than auto_ptr is to
+ let readers of your code know that you intend "resource acquisition is
+ initialization" to be applied only for the current scope, and have no intent to
+ transfer ownership. A secondary reason to use scoped_ptr is to prevent a later maintenance
+ programmer from adding a function that transfers ownership by returning the auto_ptr,
+ because the maintenance programmer saw auto_ptr, and assumed ownership
+ could safely be transferred. Think of bool vs int. We all know that under the covers bool
+ is usually just an int. Indeed, some argued against including bool
+ in the C++ standard because of that. But by coding bool rather than int,
+ you tell your readers what your intent is. Same with scoped_ptr; by
+ using it you are signaling intent. It has been suggested that scoped_ptr<T> is equivalent to std::auto_ptr<T>
+ const. Ed Brey pointed out, however, that reset will not work on
+ a std::auto_ptr<T> const. One common usage of scoped_ptr is to implement a handle/body (also called
+ pimpl) idiom which avoids exposing the body (implementation) in the header
+ file. The scoped_ptr_example_test.cpp sample
+ program includes a header file, scoped_ptr_example.hpp,
+ which uses a scoped_ptr<> to an incomplete type to hide the
+ implementation. The instantiation of member functions which require a complete
+ type occurs in the scoped_ptr_example.cpp implementation
+ file. Q. Why doesn't scoped_ptr have a release() member? Revised
+ 17 September 2002 Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler.
+ Copyright 2002 Peter Dimov. Permission to copy, use, modify, sell and
+ distribute this document is granted provided this copyright notice appears in
+ all copies. This document is provided "as is" without express or implied
+ warranty, and with no claim as to its suitability for any purpose.
-
-scoped_ptr class template
Synopsis
-
-namespace boost {
+
+
+ scoped_ptr
+ class template
Synopsis
+ namespace boost {
template<typename T> class scoped_ptr : noncopyable {
@@ -53,7 +40,7 @@ pointed to. T must meet the smart pointer
typedef T element_type;
explicit scoped_ptr(T * p = 0); // never throws
- ~scoped_ptr(); // never throws
+ ~scoped_ptr(); // never throws
void reset(T * p = 0); // never throws
@@ -67,75 +54,59 @@ pointed to. T must meet the smart pointer
template<typename T> void swap(scoped_ptr<T> & a, scoped_ptr<T> & b); // never throws
}
-
-Members
-
-element_type
-typedef T element_type;
-constructors
-explicit scoped_ptr(T * p = 0); // never throws
-destructor
-~scoped_ptr(); // never throws
-reset
-void reset(T * p = 0); // never throws
-indirection
-T & operator*() const; // never throws
-T * operator->() const; // never throws
-get
-T * get() const; // never throws
-swap
-void swap(scoped_ptr & b); // never throws
-Free Functions
-
-swap
-template<typename T> void swap(scoped_ptr<T> & a, scoped_ptr<T> & b); // never throws
-Example
-
-
-
+ #include <boost/scoped_ptr.hpp>
+
Members
+ element_type
+ typedef T element_type;
+ constructors
+ explicit scoped_ptr(T * p = 0); // never throws
+ destructor
+ ~scoped_ptr(); // never throws
+ reset
+ void reset(T * p = 0); // never throws
+ indirection
+ T & operator*() const; // never throws
+ T * operator->() const; // never throws
+ get
+ T * get() const; // never throws
+ swap
+ void swap(scoped_ptr & b); // never throws
+ Free Functions
+ swap
+ template<typename T> void swap(scoped_ptr<T> & a, scoped_ptr<T> & b); // never throws
+ Example
+
+
-
-#include <boost/scoped_ptr.hpp>
#include <iostream>
-struct Shoe { ~Shoe() { std::cout << "Buckle my shoe\n"; } };
+struct Shoe { ~Shoe() { std::cout << "Buckle my shoe\n"; } };
class MyClass {
boost::scoped_ptr<int> ptr;
@@ -151,67 +122,55 @@ void main()
std::cout << my_instance.add_one() << '\n';
std::cout << my_instance.add_one() << '\n';
}
-
-
+ 1
+
+
-
-1
2
Buckle my shoe
-Rationale
-
-Handle/Body Idiom
-
-Frequently Asked Questions
-
-
-A. Because the point of scoped_ptr is to signal intent, not
-to transfer ownership. Use std::auto_ptr if ownership transfer is
-required.
-
-Rationale
+ Handle/Body Idiom
+ Frequently Asked Questions
+
+ A. When reading source code, it is valuable to be able to draw
+ conclusions about program behavior based on the types being used. If scoped_ptr
+ had a release() member, it would become possible to transfer ownership out of
+ its scope, weakening its role as a way of limiting resource lifetime to a given
+ scope. Use std::auto_ptr where transfer of ownership is
+ required. (supplied by Dave Abrahams)
+
Normally, a shared_array cannot correctly hold a pointer to a single - dynamically allocated object. See shared_ptr - for that usage.
-Because the implementation uses reference counting, shared_array will not - work correctly with cyclic data structures. For example, if main() holds - a shared_array to A, which directly or indirectly holds a shared_array - back to A, A's use count will be 2. Destruction of the original shared_array +
Normally, a shared_array cannot correctly hold a pointer to an object + that has been allocated with the non-array form of new. See + shared_ptr for that usage.
+Because the implementation uses reference counting, cycles of shared_array + instances will not be reclaimed. For example, if main() holds a shared_array + to A, which directly or indirectly holds a shared_array back to A, + A's use count will be 2. Destruction of the original shared_array will leave A dangling with a use count of 1.
A shared_ptr to a std::vector is an alternative to a shared_array that is a bit heavier duty but far more flexible.
diff --git a/shared_ptr.htm b/shared_ptr.htm index dce72c4..291005f 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -150,9 +150,12 @@ void bad()[It might be convenient to relax the requirements on shared_ptr's signature, allowing an additional, defaulted, template parameter; the parameter can encode the threading model, for example. This would help in detecting - possible ODR violations. On the other hand, using shared_ptr as - an argument to a template template parameter requires an exact signature - match.]
+ possible ODR violations. +On the other hand, using shared_ptr as an argument to + a template template parameter requires an exact signature match. Metaprogramming + experts tend to deemphasize template template parameters as they are too + inflexible, but the alternative is typically an std::allocator::rebind-type + "hack".]
typedef T element_type;@@ -229,18 +232,18 @@ void bad() pointer users.]
template<typename Y, typename D> shared_ptr(Y * p, D d);
-Requirements: p must be convertible to T *. The copy - constructor and destructor of D must not throw. The expression
d2(p)
, - where d2 is a copy of d, must be well-formed, - must not invoke undefined behavior, and must not throw exceptions. +Requirements: p must be convertible to T *. D + must be CopyConstructible. The copy constructor and destructor + of D must not throw. The expression
d(p)
must be + well-formed, must not invoke undefined behavior, and must not throw exceptions.Effects: Constructs a shared_ptr, storing a copy of p and d.
Postconditions: use count is 1.
Throws: std::bad_alloc.
Exception safety: If an exception is thrown,
-d(p)
is called.Notes: When the the time comes to delete the object pointed to by p, -
+d2(p)
is invoked, where d2 is the stored copy of - d.Notes: When the the time comes to delete the object pointed to by p, + the stored copy of d is invoked with the stored copy of p + as an argument.
[Custom deallocators allow a factory function returning a shared_ptr
to insulate the user from its memory allocation strategy. Since the deallocator
@@ -311,9 +314,10 @@ template<typename Y> shared_ptr & operator=(shared_ptr<Y> const
template<typename Y> shared_ptr & operator=(std::auto_ptr<Y> & r);
Effects: Equivalent to Notes: The implementation is free to meet the effects (and the implied
- guarantees) via different means, without creating a temporary. In particular,
- in the example: Notes: The use count updates caused by the temporary object construction
+ and destruction are not considered observable side effects, and the
+ implementation is free to meet the effects (and the implied guarantees) via
+ different means, without creating a temporary. In particular, in the example: both assignments may be no-ops. [Some experts consider the note to be redundant, as it appears to essentially
+ mirror the "as if" rile. However, experience suggests that when C++ code is
+ used to describe effects, it is often misinterpreted as required
+ implementation. In addition, it is not entirely clear whether the "as if" rule
+ actually applies here, so it's better to be explicit about the possible
+ optimizations.]
+ shared_ptr(r).swap(*this)
.
shared_ptr<int> p(new int);
shared_ptr<void> q(p);
@@ -322,6 +326,12 @@ q = p;
reset
void reset();
@@ -649,7 +659,7 @@ int * p = a.release();
implementation or a linked list implementation, or some other specific
implementation. This is not the intent.
Revised +
Revised 23 July 2002
Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler. Copyright 2002 Peter Dimov. Permission to copy, use, modify, sell and diff --git a/smart_ptr.htm b/smart_ptr.htm index 1e045f1..9e5357a 100644 --- a/smart_ptr.htm +++ b/smart_ptr.htm @@ -1,207 +1,168 @@ - - -
- -Smart pointers are objects which store pointers to dynamically allocated -(heap) objects. They behave much like built-in C++ pointers except that -they automatically delete the object pointed to at the appropriate -time. Smart pointers are particularly useful in the face of exceptions as -they ensure proper destruction of dynamically allocated objects. They can also -be used to keep track of dynamically allocated objects shared by multiple -owners.
- -Conceptually, smart pointers are seen as owning the object pointed to, and -thus responsible for deletion of the object when it is no longer needed.
- -The smart pointer library provides five smart pointer class templates:
- -scoped_ptr | -<boost/scoped_ptr.hpp> | -Simple sole ownership of single objects. Noncopyable. | -
scoped_array | -<boost/scoped_array.hpp> | -Simple sole ownership of arrays. Noncopyable. | -
shared_ptr | -<boost/shared_ptr.hpp> | -Object ownership shared among multiple pointers | -
shared_array | -<boost/shared_array.hpp> | -Array ownership shared among multiple pointers. | -
weak_ptr | -<boost/weak_ptr.hpp> | -Non-owning observers of an object owned by shared_ptr. | -
These templates are designed to complement the std::auto_ptr template.
- -They are examples of the "resource acquisition is initialization" -idiom described in Bjarne Stroustrup's "The C++ Programming Language", -3rd edition, Section 14.4, Resource Management.
- -A test program, smart_ptr_test.cpp, is -provided to verify correct operation.
- -A page on compatibility with older versions of -the Boost smart pointer library describes some of the changes since earlier versions -of the smart pointer implementation.
- -A page on smart pointer timings will be of -interest to those curious about performance issues.
- -These smart pointer class templates have a template parameter, T, which -specifies the type of the object pointed to by the smart pointer. The -behavior of the smart pointer templates is undefined if the destructor or operator delete -for objects of type T throw exceptions.
- -T may be an incomplete type at the point of smart pointer -declaration. Unless otherwise specified, it is required that T -be a complete type at points of smart pointer instantiation. Implementations are -required to diagnose (treat as an error) all violations of this requirement, -including deletion of an incomplete type. -See the description of the checked_delete -function template.
- -The requirements on T are carefully crafted to maximize safety -yet allow handle-body (also called pimpl) and similar idioms. In these idioms a -smart pointer may appear in translation units where T is an -incomplete type. This separates interface from implementation and hides -implementation from translation units which merely use the interface. -Examples described in the documentation for specific smart pointers illustrate -use of smart pointers in these idioms.
- -Note that scoped_ptr requires that T be a complete type -at destruction time, but shared_ptr does not.
- -Several functions in these smart pointer classes are specified as having -"no effect" or "no effect except such-and-such" if an -exception is thrown. This means that when an exception is thrown by -an object of one of these classes, the entire program state remains the same as -it was prior to the function call which resulted in the exception being -thrown. This amounts to a guarantee that there are no detectable side -effects. Other functions never throw exceptions. The only exception -ever thrown by functions which do throw (assuming T meets the -common requirements) is std::bad_alloc, -and that is thrown only by functions which are explicitly documented as possibly -throwing std::bad_alloc.
- -Exception-specifications are not used; see -exception-specification -rationale.
- -All the smart pointer templates contain member functions which can never throw exceptions,
-because they neither throw exceptions themselves nor call other functions which
-may throw exceptions. These members are indicated by a comment:
-// never throws
.
Functions which destroy objects of the pointed to type are prohibited from -throwing exceptions by the common requirements.
- -January 2002. Peter Dimov reworked all four classes, adding features, fixing bugs, -and splitting them into four separate headers, and added weak_ptr. See the -compatibility page for a summary of the changes.
- -May 2001. Vladimir Prus suggested requiring a complete type on -destruction. Refinement evolved in discussions including Dave Abrahams, -Greg Colvin, Beman Dawes, Rainer Deyke, Peter Dimov, John Maddock, Vladimir Prus, -Shankar Sai, and others.
- -November 1999. Darin Adler provided operator ==, operator !=, and std::swap -and std::less specializations for shared types.
- -September 1999. Luis Coelho provided shared_ptr::swap and shared_array::swap
- -May 1999. In April and May, 1999, Valentin Bonnard and David Abrahams -made a number of suggestions resulting in numerous improvements.
- -October 1998. In 1994 Greg Colvin proposed to the C++ Standards Committee -classes named auto_ptr and counted_ptr which -were very similar to what we now call scoped_ptr and shared_ptr. -The committee document was 94-168/N0555, Exception Safe Smart Pointers. In -one of the very few cases where the Library Working Group's recommendations were -not followed by the full committee, counted_ptr was rejected -and surprising transfer-of-ownership semantics were added to auto_ptr.
- -Beman Dawes proposed reviving the original semantics under the names safe_ptr -and counted_ptr at an October, 1998, meeting of Per Andersson, -Matt Austern, Greg Colvin, Sean Corfield, Pete Becker, Nico Josuttis, Dietmar -Kühl, Nathan Myers, Chichiang Wan and Judy Ward. During the discussion, -the four class names were finalized, it was decided that there was no need to -exactly follow the std::auto_ptr interface, and various -function signatures and semantics were finalized.
- -Over the next three months, several implementations were considered for shared_ptr, -and discussed on the boost.org mailing -list. The implementation questions revolved around the reference count -which must be kept, either attached to the pointed to object, or detached -elsewhere. Each of those variants have themselves two major variants: - -
Each implementation technique has advantages and disadvantages. We went -so far as to run various timings of the direct and indirect approaches, and -found that at least on Intel Pentium chips there was very little measurable -difference. Kevlin Henney provided a paper he wrote on "Counted Body -Techniques." Dietmar Kühl suggested an elegant partial template -specialization technique to allow users to choose which implementation they -preferred, and that was also experimented with.
- -But Greg Colvin and Jerry Schwarz argued that "parameterization will -discourage users", and in the end we choose to supply only the direct -implementation.
- -Revised 4 February 2002 + 4 February 2002
- -Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler. -Permission to copy, use, -modify, sell and distribute this document is granted provided this copyright -notice appears in all copies. This document is provided "as is" -without express or implied warranty, and with no claim as to its suitability for -any purpose.
- - - +Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler. + Permission to copy, use, modify, sell and distribute this document is granted + provided this copyright notice appears in all copies. This document is provided + "as is" without express or implied warranty, and with no claim as to its + suitability for any purpose.
+