From a8bb455df7a8ff67028c52729ea31eb3dea5f93f Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 23 Sep 2002 13:22:38 +0000 Subject: [PATCH] Fixes, notes. [SVN r15486] --- shared_ptr.htm | 70 ++++++++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/shared_ptr.htm b/shared_ptr.htm index 291005f..1a91e46 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -47,14 +47,14 @@ where U is an accessible base of T, and to shared_ptr<void>.

Best Practices

-

A simple guideline that nearly eliminates the possibility of memory leaks +

A simple guideline that nearly eliminates the possibility of memory leaks is: always use a named smart pointer variable to hold the result of new. Every occurence of the new keyword in the code should have the form:

shared_ptr<T> p(new Y);

It is, of course, acceptable to use another smart pointer in place of shared_ptr above; having T and Y be the same type, or - passing arguments to Y's constructor is also OK.

+ passing arguments to Y's constructor is also OK.

If you observe this guideline, it naturally follows that you will have no explicit deletes; try/catch constructs will be rare.

@@ -96,23 +96,23 @@ void bad() typedef T element_type; - shared_ptr(); + shared_ptr(); template<typename Y> explicit shared_ptr(Y * p); template<typename Y, typename D> shared_ptr(Y * p, D d); - ~shared_ptr(); // never throws + ~shared_ptr(); // never throws - shared_ptr(shared_ptr const & r); // never throws - template<typename Y> shared_ptr(shared_ptr<Y> const & r); // never throws - explicit shared_ptr(weak_ptr const & r); - template<typename Y> shared_ptr(std::auto_ptr<Y> & r); + shared_ptr(shared_ptr const & r); // never throws + template<typename Y> shared_ptr(shared_ptr<Y> const & r); // never throws + template<typename Y> explicit shared_ptr(weak_ptr<Y> const & r); + template<typename Y> explicit shared_ptr(std::auto_ptr<Y> & r); shared_ptr & operator=(shared_ptr const & r); // never throws template<typename Y> shared_ptr & operator=(shared_ptr<Y> const & r); // never throws template<typename Y> shared_ptr & operator=(std::auto_ptr<Y> & r); - void reset (); - template<typename Y> void reset (Y * p); - template<typename Y> template<typename D> void reset(Y * p, D d); + void reset(); + template<typename Y> void reset(Y * p); + template<typename Y, typename D> void reset(Y * p, D d); T & operator*() const; // never throws T * operator->() const; // never throws @@ -121,9 +121,9 @@ void bad() bool unique() const; // never throws long use_count() const; // never throws - operator unspecified-bool-type () const; // never throws + operator unspecified-bool-type() const; // never throws - void swap(shared_ptr<T> & b); // never throws + void swap(shared_ptr & b); // never throws }; template<typename T, typename U> @@ -147,12 +147,12 @@ void bad() shared_ptr<T> shared_polymorphic_downcast(shared_ptr<U> const & r); // never throws } -

[It might be convenient to relax the requirements on shared_ptr's +

[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. Metaprogramming +

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".]

@@ -222,13 +222,13 @@ void bad() of intrusive counting. shared_from_this would no longer be O(1), which is a concern for some users, although I do not expect any performance problems, since the operation is rare. Maintaining a global - map is difficult; it needs to be initialized before any shared_ptr - instances are constructed, and the initialization needs to be thread safe. + map is difficult; it needs to be initialized before any shared_ptr + instances are constructed, and the initialization needs to be thread safe. In addition, under the Windows dynamic library model, it is possible for several maps to exist.

It is not yet clear which implementation should be used, or whether the - specification should allow both; nevertheless, the ability to make a shared_ptr - from this is considered essential by experienced smart + specification should allow both; nevertheless, the ability to make a shared_ptr + from this is considered essential by experienced smart pointer users.]

template<typename Y, typename D> shared_ptr(Y * p, D d);
@@ -253,9 +253,18 @@ void bad() to a statically allocated object.

The support for custom deallocators does not impose significant overhead. Other shared_ptr features still require a deallocator to be kept.

-

The requirement that the copy constructor of D does not throw is too - strong. It will be removed when some core language issues are resolved - (cv-qualified function types, partial ordering clarifications.)]

+

The requirement that the copy constructor of D does not throw comes from + the pass by value. If the copy constructor throws, the pointer is leaked. + Removing the requirement requires a pass by (const) reference. The problems are + that (1) pass by value conveniently changes functions (function references) to + function pointers (this has to be performed manually otherwise and some + compilers may not be able to do it) and (2) const references don't currently + (per the standard) bind to functions. This can be solved (I think) but it + requires an overload set that breaks on many compilers due to 14.5.5.2 problems + (and of course it will break on compilers that don't do partial ordering at + all.)

+

The requrement will be removed when the aforementioned issues are + resolved.]

shared_ptr(shared_ptr const & r); // never throws
 template<typename Y> shared_ptr(shared_ptr<Y> const & r); // never throws
@@ -267,7 +276,7 @@ template<typename Y> shared_ptr(shared_ptr<Y> const & r); // nev

[The postcondition will be relaxed when a default-constructed shared_ptr is being copied.]

-
explicit shared_ptr(weak_ptr const & r);
+
template<typename Y> explicit shared_ptr(weak_ptr<Y> const & r);

Effects: Constructs a shared_ptr, as if by storing a copy of the pointer stored in r.

@@ -389,7 +398,7 @@ q = p;

conversions

operator unspecified-bool-type () const; // never throws
-

Returns: an unspecified value that, when used in boolean contexts, +

Returns: an unspecified value that, when used in boolean contexts, is equivalent to get() != 0.

Throws: nothing.

Notes: This conversion operator allows shared_ptr objects to be @@ -423,7 +432,7 @@ q = p;

template<typename T>
   bool operator<(shared_ptr<T> const & a, shared_ptr<T> const & b); // never throws
-

Returns: an unspecified value such that operator< is a +

Returns: an unspecified value such that operator< is a strict weak ordering as described in section 25.3 [lib.alg.sorting] of the C++ standard.

Throws: nothing.

@@ -436,7 +445,7 @@ q = p; standard algorithms use operator< instead of std::less for comparisons when a predicate is not supplied. Composite objects, like std::pair, also implement their operator< in terms of their contained - subobjects' operator<.

+ subobjects' operator<.

The rest of the comparison operators are omitted by design.]

swap

template<typename T>
@@ -546,8 +555,8 @@ q = p;
 			type.

Thread Safety

shared_ptr objects offer the same level of thread safety as - built-in types. A shared_ptr instance can be "read" - (accessed using only const operations) simultaneously by multiple threads. + built-in types. A shared_ptr instance can be "read" + (accessed using only const operations) simultaneously by multiple threads. Different shared_ptr instances can be "written to" (accessed using mutable operations such as operator= or reset) simultaneosly by multiple threads (even when these instances are copies, and @@ -659,8 +668,7 @@ int * p = a.release(); implementation or a linked list implementation, or some other specific implementation. This is not the intent.


-

Revised - 23 July 2002

+

Revised $Date$

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