|
Jason Stredwick
jason.stredwick@gmail.com Current Residence: Bothell, WA 98011 |
|
|
Summary:After many frustrating instances where I wanted to change a reference, I decided to try my hand at resolving this issue. First, I found that a reference can be conditionally assigned by using the ?: operator, at least in g++4 and Visual Studio 2005, if not potentially others. For example: int x = 25; int y = 37; int &r1 = (x < y) ? x : y; x = 45; int &r2 = (x < y) ? x : y; cout << r1 << " " << r2 << endl; The are many situations that arise where I would like to be able to change a reference. One such situation is when I want to assign a reference based on user input or system state. Another situation is when I want to store a reference as class member data rather than a pointer. This situation can arise from the requirement to have a non-null handle to some instantiated object. A pointer lacks certain guarantees and thus you have to constantly check to make sure it maintains its non-null status. A reference on the other hand guarantees that if it was initialized, it is non-null. There are exceptions, such as those rare occasions when you assign allocated memory to a reference and then delete the memory. However, this is a problem for standard reference variables as well. Finally, it may be advantageous in the future to have a reference as a user defined class rather than a builtin type. To find a solution to this problem, I thought I would try my hand at recreating a reference in the form of a class, and then extend it such that the reference itself can change. These classes follow: Ref.h ReRef.h RefTest.cpp (A test/sample program) There are commented out lines that say Compiler Error in the test. If you uncomment them, they should give you a compiler error. There is a potential problem if they do not give an error, and I consider the lack of error to violate the correct workings of the class. The Ref class is meant to be a transparent replacement of an actual reference. * The Ref class must be initialized with a reference or another Ref. * Assignment changes the value of the reference, not what it points to. * There are casting operators to the actual reference of the encapsulated type. * There is an address operator which returns a pointer to the encapsulated data. * Due to the possible need to have the address of the Ref class itself, there is the Address method. The ReRef class is the same as the Ref class, except it allows the reference to change by calling the Reassign method. Also, because it inherits from Ref, it can be constructed and reassigned with a Ref, but not vice versa. Source CodeRef.h
/*
* Copyright 2006 Jason Stredwick.
* Distributed under the Boost Software License, Version 1.0. (See
* LICENSE information at the bottom of this file or the copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef __Ref_h__
#define __Ref_h__
/*
* Ref is intended to be the equivalent to a reference and transparent to
* the user. It must be initialized with a reference or another Ref.
* Assignment changes the value of its data not what it is pointing to.
* The casting operators allow for seemless use of this class with global
* operators.
* Note that the cast operator may give a warning on older compilers.
* This class was verified on g++4 and visual studio 2005.
* Jason Stredwick May 7, 2006
* Added typedef T type as public member. Also, realized and tested that
* boost::addressof works for determining the address of Ref too, not just
* the member method. However, unless one is using the older MSVC
* the include hierarchy can be removed completely.
* Jason Stredwick May 5, 2006
* Realized I needed a way to get a pointer of the Ref<T> variable, so
* I created the Address method.
* Jason Stredwick May 5, 2006
* Figured out how I wanted to handle Ref<const T> and const Ref<T>.
* Const references are done ther with const Ref<T>,
* const Ref<const T>, or Ref<const T>.
* Added a const version of operator&.
* Removed test for self in operator=, which is not necessary.
* Jason Stredwick April 6, 2006 Finalized first version of Ref.
*/
template <typename T>
class Ref
{
protected:
T *d_t;
public:
typedef T type;
private:
// No default construction
Ref(void);
public:
Ref(T &t) : d_t(&t) { return; }
Ref(const Ref<T> &r) : d_t(r.d_t) { return; }
~Ref(void) { d_t = 0; return; }
// Assignment operators
T &operator=(const Ref<T> &r) {
*d_t = *(r.d_t);
return *d_t;
}
T &operator=(const T &t) { *d_t = t; return *d_t; }
// Address operator
const T * operator&() const { return d_t; }
T * operator&() { return d_t; }
// Cast operators
// Allows for seemless use with global operators, though
// prior to g++3.3, may give warning
operator const T &() const { return *d_t; }
operator T &() { return *d_t; }
const Ref
ReRef.h
/*
* Copyright 2006 Jason Stredwick.
* Distributed under the Boost Software License, Version 1.0. (See
* LICENSE information at the bottom of this file or the copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef __ReRef_h__
#define __ReRef_h__
/*
* The ReRef class is based on the Ref class. Ref is intended to be the
* equivalent to a reference and transparent to the user. It must be
* initialized with a reference, Ref, or ReRef. Assignment changes
* the value of its data not what it is pointing to. The casting
* operators allow for seemless use of this class with global operators.
* The ReRef class is exactly the same as the Ref class but includes one
* additional feature, the ability to change what the reference points
* to. The Reassign method is just like the constructors, it takes only
* a variable reference, a Ref, or a ReRef.
* Note that the cast operator may give a warning on older compilers.
* This class was verified on g++4 and visual studio 2005.
* Jason Stredwick May 5, 2006
* Realized I needed a way to get a pointer of the Ref<T> variable, so
* I created the Address method.
* Jason Stredwick May 5, 2006
* Figured out how I wanted to handle ReRef<const T> and const ReRef<T>.
* Const references are done ther with const ReRef<T>,
* const ReRef<const T>, or ReRef<const T>.
* Added a const version of operator&.
* Removed test for self in operator=, which is not necessary.
* Jason Stredwick April 18, 2006 Modified ReRef to inherit Ref in order
* to handle the implicit construction of one with the other.
* Jason Stredwick April 6, 2006 Finalized first version of Ref and ReRef.
*/
#include "Ref.h"
template <typename T>
class ReRef : public Ref<T>
{
private:
// No default construction
ReRef(void);
public:
ReRef(T &t) : Ref<T>(t) { return; }
ReRef(const Ref<T> &r) : Ref<T>(r) { return; }
ReRef(const ReRef<T> &r) : Ref<T>(r) { return; }
~ReRef(void) { return; }
// Assignment operators
T &operator=(const ReRef<T> &r)
{
*Ref<T>::d_t = *(r.Ref<T>::d_t);
return *Ref<T>::d_t;
}
T &operator=(const Ref<T> &r)
{
*Ref<T>::d_t = *(r.Ref<T>::d_t);
return *Ref<T>::d_t;
}
T &operator=(const T &t)
{
*Ref<T>::d_t = t;
return *Ref<T>::d_t;
}
// Address operator
const T * operator&() const { return Ref<T>::d_t; }
T * operator&() { return Ref<T>::d_t; }
// Cast operators
// Allows for seemless use with global operators, though
// prior to g++3.3, may give warning
operator const T &() const { return *Ref<T>::d_t; }
operator T &() { return *Ref<T>::d_t; }
const ReRef
|