Author: wyoung
Date: Thu Nov 29 08:49:48 2007
New Revision: 1920
URL: http://svn.gna.org/viewcvs/mysqlpp?rev=1920&view=rev
Log:
Applied much of the RefCountedPointer redesign by Jonathan Wakely
<[EMAIL PROTECTED]>. Pretty much everything but the safe-bool
stuff, which we did differently recently with the change from operator
bool() and operator !() to operator void*().
Modified:
trunk/CREDITS
trunk/lib/refcounted.h
Modified: trunk/CREDITS
URL:
http://svn.gna.org/viewcvs/mysqlpp/trunk/CREDITS?rev=1920&r1=1919&r2=1920&view=diff
==============================================================================
--- trunk/CREDITS (original)
+++ trunk/CREDITS Thu Nov 29 08:49:48 2007
@@ -45,6 +45,9 @@
examples/deadlock.cpp to test that this feature does what it is
supposed to.
+ Jonathan Wakely <[EMAIL PROTECTED]> redesigned the
+ internals of RefCountedPointer for greater exception safety.
+
Here are the personal credits from the old 1.7.9 documentation,
apparently written by Kevin Atkinson:
Modified: trunk/lib/refcounted.h
URL:
http://svn.gna.org/viewcvs/mysqlpp/trunk/lib/refcounted.h?rev=1920&r1=1919&r2=1920&view=diff
==============================================================================
--- trunk/lib/refcounted.h (original)
+++ trunk/lib/refcounted.h Thu Nov 29 08:49:48 2007
@@ -3,9 +3,10 @@
/// class
/***********************************************************************
- Copyright (c) 2007 by Educational Technology Resources, Inc.
- Others may also hold copyrights on code in this file. See the
- CREDITS file in the top directory of the distribution for details.
+ Copyright (c) 2007 by Educational Technology Resources, Inc. and
+ (c) 2007 by Jonathan Wakely. Others may also hold copyrights on
+ code in this file. See the CREDITS file in the top directory of
+ the distribution for details.
This file is part of MySQL++.
@@ -30,6 +31,8 @@
#include "type_info.h"
+#include <algorithm>
+#include <memory>
#include <string>
namespace mysqlpp {
@@ -99,16 +102,23 @@
/// object's useless until you vivify it with operator =() or assign().
explicit RefCountedPointer(T* c) :
counted_(c),
- refs_(c ? new size_t(1) : 0)
- {
+ refs_(0)
+ {
+ std::auto_ptr<T> exception_guard(counted_);
+ if (counted_) {
+ refs_ = new size_t(1);
+ }
+ exception_guard.release(); // previous new didn't throw
}
/// \brief Copy constructor
RefCountedPointer(const ThisType& other) :
- counted_(0), // yes, this is required! see assign()
- refs_(0)
- {
- assign(other);
+ counted_(other.counted_),
+ refs_(other.counted_ ? other.refs_ : 0)
+ {
+ if (counted_) {
+ ++(*refs_);
+ }
}
/// \brief Destructor
@@ -117,63 +127,56 @@
/// drops to 0.
~RefCountedPointer()
{
- detach();
+ if (refs_ && (--(*refs_) == 0)) {
+ Destroyer()(counted_);
+ delete refs_;
+ }
}
/// \brief Sets (or resets) the pointer to the counted object.
///
- /// Before we do the actual assignment, we decrement the previous
- /// managed object's refcount. If it falls to 0, it's destroyed.
- ///
- /// If the refcount is >= 2 when we are called, the other users of
- /// the managed memory will see no difference; the internal refcount
- /// will just be 1 lower, which is imperceptible from the outside.
- /// Only this object sees a change in what's being pointed to.
- void assign(T* c)
- {
- detach();
-
- if (c) {
- counted_ = c;
- refs_ = new size_t(1);
- }
- else {
- counted_ = 0;
- refs_ = 0;
- }
+ /// If we are managing a pointer, this decrements the refcount for
+ /// it and destroys the managed object if the refcount falls to 0.
+ ///
+ /// This is a no-op if you pass the same pointer we're already
+ /// managing.
+ ThisType& assign(T* c)
+ {
+ if (c != counted_) {
+ // The create-temporary-and-swap idiom lets us keep
memory
+ // allocation in the ctor and deallocation in the dtor
so
+ // we don't leak in the face of an exception.
+ ThisType(c).swap(*this);
+ }
+ return *this;
}
/// \brief Copy an existing refcounted pointer
///
- /// This just copies the pointer to the underlying counted pointer
- /// and increases the reference count.
- ///
- /// If this object already pointed to managed memory, we decrement
- /// the refcount for it first, and destroy the managed memory block
- /// if the refcount falls to 0.
- void assign(const ThisType& other)
- {
- detach();
-
- if (other.counted_ && other.refs_) {
- counted_ = other.counted_;
- refs_ = other.refs_;
- ++(*refs_);
- }
- else {
- counted_ = 0;
- refs_ = 0;
- }
+ /// If we are managing a pointer, this decrements the refcount for
+ /// it and destroys the managed object if the refcount falls to 0.
+ /// Then we increment the other object's reference count and copy
+ /// that refcount and the managed pointer into this object.
+ ///
+ /// This is a no-op if you pass a reference to this same object.
+ ThisType& assign(const ThisType& other)
+ {
+ if (&other != this) {
+ // The create-temporary-and-swap idiom lets us keep
memory
+ // allocation in the ctor and deallocation in the dtor
so
+ // we don't leak in the face of an exception.
+ ThisType(other).swap(*this);
+ }
+ return *this;
}
/// \brief Set (or reset) the pointer to the counted object
///
- /// This is essentially the same thing as assign(T*). The
- /// choice between the two is just a matter of syntactic preference.
+ /// This is essentially the same thing as assign(T*). The choice
+ /// between the two is just a matter of syntactic preference.
ThisType& operator =(T* c)
{
- assign(c);
- return *this;
+ return assign(c);
}
/// \brief Copy an existing refcounted pointer
@@ -183,8 +186,7 @@
/// preference.
ThisType& operator =(const ThisType& rhs)
{
- assign(rhs);
- return *this;
+ return assign(rhs);
}
/// \brief Access the object through the smart pointer
@@ -243,21 +245,17 @@
return counted_;
}
+ /// \brief Exchange our managed memory with another pointer.
+ ///
+ /// \internal This exists primarily to implement assign() in an
+ /// exception-safe manner.
+ void swap(ThisType& other)
+ {
+ std::swap(counted_, other.counted_);
+ std::swap(refs_, other.refs_);
+ }
+
private:
- /// \brief Detach ourselves from the managed memory block.
- ///
- /// If we are managing memory, decreases the reference count and
- /// destroys the memory if the counter falls to 0.
- void detach()
- {
- if (refs_ && (--(*refs_) == 0)) {
- Destroyer()(counted_);
- delete refs_;
- counted_ = 0;
- refs_ = 0;
- }
- }
-
/// \brief Pointer to the reference-counted object
T* counted_;
_______________________________________________
Mysqlpp-commits mailing list
[email protected]
https://mail.gna.org/listinfo/mysqlpp-commits