1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
|
/*
Copyright (C) 2000, 2001, 2002 RiskMap srl
This file is part of QuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://quantlib.org/
QuantLib is free software: you can redistribute it and/or modify it under the
terms of the QuantLib license. You should have received a copy of the
license along with this program; if not, please email ferdinando@ametrano.net
The license is also available online at http://quantlib.org/html/license.html
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the license for more details.
*/
/*! \file handle.hpp
\brief Reference-counted pointer
\fullpath
ql/%handle.hpp
*/
// $Id: handle.hpp,v 1.9 2002/03/06 07:16:06 sadrejeb Exp $
#ifndef quantlib_handle_h
#define quantlib_handle_h
#include <ql/errors.hpp>
// The implementation of this class is taken from
// "The C++ Programming Language", 3rd edition, B.Stroustrup
namespace QuantLib {
template <class T> class Handle;
class HandleCopier {
public:
template <class T, class U>
static void copy(const Handle<T>& from, const Handle<U>& to) {
if (from.n_ != to.n_) {
// if to was the last reference to its object...
if (--(*to.n_) == 0) {
// ...delete the latter and the counter
if (to.ptr_ != 0 && to.owns_)
delete to.ptr_;
delete to.n_;
}
// cast to the new type - the resulting pointer will
// be null if the two types are not compatible
to.ptr_ = dynamic_cast<U*>(from.ptr_);
to.n_ = from.n_;
to.owns_ = from.owns_;
(*to.n_)++;
}
}
};
//! Reference-counted pointer
/*! This class acts as a proxy to a pointer contained in it. Such pointer
is owned by the handle, i.e., the handle will be responsible for its
deletion, unless explicitly stated by the programmer.
A count of the references to the contained pointer is incremented
every time a handle is copied, and decremented every time a handle is
deleted or goes out of scope. When the handle owns the pointer, this
mechanism ensures on one hand, that the pointer will not be
deallocated as long as a handle refers to it, and on the other hand,
that it will be deallocated when no more handles do.
\note The implementation of this class was originally taken from
"The C++ Programming Language", 3rd ed., B.Stroustrup,
Addison-Wesley,
1997.
\warning This mechanism will break and result in untimely
deallocation of the pointer (and very possible death of your
executable) if two handles are explicitly initialized with
the same pointer, as in
\code
SomeObj* so = new SomeObj;
Handle<SomeObj> h1(so);
Handle<SomeObj> h2 = h1; // this is safe.
Handle<SomeObj> h3(so); // this is definitely not.
\endcode
It is good practice to create the pointer and immediately
pass it to the handle, as in
\code
Handle<SomeObj> h1(new SomeObj); // this is as safe as can be.
\endcode
\warning When the programmer keeps the ownership of the pointer, as
explicitly declared in
\code
SomeObj so;
Handle<SomeObj> h(&so,false);
\endcode
it is responsibility of the programmer to make sure that the
object remain in scope as long as there are handles pointing
to it. Also, the programmer must explicitly delete the
object if required.
*/
template <class T>
class Handle {
friend class HandleCopier;
public:
//! \name constructors, destructor, and assignment
//@{
//! Constructor taking a pointer.
/*! If <b>owns</b> is set to <tt>true</tt> (the default), the handle
will be responsible for the deletion of the pointer. If it is
set to <tt>false</tt>, the programmer must make sure that the
pointed object remains in scope for the lifetime of the handle
and its copies. Destruction of the object is also responsibility
of the programmer.
It is advised that handles be used with <tt>owns = false</tt>
only in a controlled an self-contained environment. Such a case
happens when an object needs to pass a handle to itself to inner
classes or bootstrappers - i.e., contained or temporary objects
whose lifetime is guaranteed not to last more than the lifetime
of the object.
*/
explicit Handle(T* ptr = 0, bool owns = true)
: ptr_(ptr), n_(new int(1)), owns_(owns) {}
template <class U>
Handle(const Handle<U>& from)
: ptr_(0), n_(new int(1)), owns_(true) {
HandleCopier::copy(from,*this);
}
Handle(const Handle& from)
: ptr_(from.ptr_), n_(from.n_), owns_(from.owns_) { (*n_)++; }
~Handle();
template <class U>
Handle& operator=(const Handle<U>& from) {
HandleCopier::copy(from,*this);
return *this;
}
Handle& operator=(const Handle& from);
//@}
//! \name Dereferencing
//@{
T& operator*() const;
T* operator->() const;
//@}
//! \name Inspectors
//@{
//! Checks if the contained pointer is actually allocated
bool isNull() const;
//! Checks if the two handles point to the same object
bool shareSameObject(const Handle<T>&) const;
//@}
private:
mutable T* ptr_;
mutable int* n_;
mutable bool owns_;
};
// inline definitions
template <class T>
inline Handle<T>::~Handle() {
if (--(*n_) == 0) {
if (ptr_ != 0 && owns_)
delete ptr_;
delete n_;
}
}
template <class T>
inline Handle<T>& Handle<T>::operator=(const Handle& from) {
if (ptr_ != from.ptr_) {
if (--(*n_) == 0) {
if (ptr_ != 0 && owns_)
delete ptr_;
delete n_;
}
ptr_ = from.ptr_;
n_ = from.n_;
owns_ = from.owns_;
(*n_)++;
}
return *this;
}
template <class T>
inline T& Handle<T>::operator*() const {
QL_REQUIRE(ptr_ != 0, "tried to dereference null handle");
return *ptr_;
}
template <class T>
inline T* Handle<T>::operator->() const {
QL_REQUIRE(ptr_ != 0, "tried to dereference null handle");
return ptr_;
}
template <class T>
inline bool Handle<T>::isNull() const {
return (ptr_ == 0);
}
template <class T>
inline bool Handle<T>::shareSameObject(const Handle<T>& h) const {
return (ptr_ == h.ptr_);
}
}
#endif
|