468 lines
12 KiB
C++
468 lines
12 KiB
C++
|
/**************************************************************************\
|
||
|
*
|
||
|
* Copyright (c) 2000 Microsoft Corporation
|
||
|
*
|
||
|
* Module Name:
|
||
|
*
|
||
|
* AutoPointers smart pointer classes library.
|
||
|
*
|
||
|
* Abstract:
|
||
|
*
|
||
|
* Implements AutoArray and AutoPointer smart pointer classes.
|
||
|
*
|
||
|
* Notes:
|
||
|
*
|
||
|
* To avoid cleanup code in our functions we need to use smart pointer classes
|
||
|
* for holding allocation results. These classes are roughly similar to std::auto_ptr,
|
||
|
* although there are differences regarding ownership, operator&, defensive code etc.
|
||
|
*
|
||
|
* Revision History:
|
||
|
*
|
||
|
* 07/18/2000 mleonov
|
||
|
* Created it.
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
#ifndef __AUTOPOINTERS_HPP_
|
||
|
#define __AUTOPOINTERS_HPP_
|
||
|
|
||
|
// The following 2 classes are very similar, except that:
|
||
|
// AutoPointer uses operator delete and provides operator->
|
||
|
// AutoArray uses operator delete[] and provides operator[]
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
///// AutoArray - Pointer to array of items with automatic freeing
|
||
|
//
|
||
|
// This class is used for storing arrays allocated using new [].
|
||
|
// For example:
|
||
|
//
|
||
|
// {
|
||
|
// AutoArray<BYTE> buffer(new BYTE[count]);
|
||
|
// if (!buffer)
|
||
|
// return OutOfMemory;
|
||
|
// buffer[0] = 0;
|
||
|
// DoSomething(buffer.Get());
|
||
|
// // buffer is automatically deallocated
|
||
|
// }
|
||
|
|
||
|
template<class T>
|
||
|
class AutoArray
|
||
|
{
|
||
|
typedef AutoArray<T> self;
|
||
|
public:
|
||
|
// This constructor is made explicit so that compiler
|
||
|
// doesn't create implicit temporaries of type AutoArray<T>
|
||
|
explicit AutoArray(T * source = 0) : Pointer(source) {}
|
||
|
|
||
|
// Copy constructor and assignment operators need to ensure that
|
||
|
// pointer is freed only once
|
||
|
AutoArray(self & rhs) : Pointer(rhs.Release()) {}
|
||
|
|
||
|
self & operator=(self & rhs)
|
||
|
{
|
||
|
SafeAssign(rhs.Release());
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
// Safe assignment for regular pointer
|
||
|
self & operator=(T * rhs)
|
||
|
{
|
||
|
SafeAssign(rhs);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
// Destructor is the whole point of having this class
|
||
|
~AutoArray()
|
||
|
{
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
// This operator is for functions which allocate pointer and return it using T **
|
||
|
T ** operator&()
|
||
|
{
|
||
|
Clear();
|
||
|
Pointer = 0;
|
||
|
return &Pointer;
|
||
|
}
|
||
|
|
||
|
// The following 2 operators are for checks for NULL
|
||
|
operator BOOL() const
|
||
|
{
|
||
|
return (Pointer != 0);
|
||
|
}
|
||
|
|
||
|
BOOL operator!() const
|
||
|
{
|
||
|
return !Pointer;
|
||
|
}
|
||
|
|
||
|
// We disallow implicit conversion to pointer because it's dangerous,
|
||
|
// for example we don't want people do explicitly delete underlying pointer
|
||
|
// operator T* () const { return Pointer; }
|
||
|
|
||
|
T & operator*() const
|
||
|
{
|
||
|
AssertNotEmpty();
|
||
|
return *Get();
|
||
|
}
|
||
|
|
||
|
// Make indexing work the same way as for built-in arrays
|
||
|
template <typename INDEXTYPE>
|
||
|
T & operator[](INDEXTYPE ndx) const
|
||
|
{
|
||
|
AssertNotEmpty();
|
||
|
return *(Get() + ndx);
|
||
|
}
|
||
|
|
||
|
// Obtain the underlying pointer
|
||
|
T * Get() const
|
||
|
{
|
||
|
return Pointer;
|
||
|
}
|
||
|
|
||
|
// Obtain the underlying pointer and release ownership,
|
||
|
// normally this is used to safely return the pointer from a function
|
||
|
// and let caller take care of deallocation
|
||
|
T * Release()
|
||
|
{
|
||
|
T * tmp = Pointer;
|
||
|
Pointer = 0;
|
||
|
return tmp;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
// Note that one should always assign a new value to Pointer after calling Clear()
|
||
|
void Clear()
|
||
|
{
|
||
|
delete[] Pointer;
|
||
|
}
|
||
|
|
||
|
void SafeAssign(T * rhs)
|
||
|
{
|
||
|
// We don't want to have 2 smart pointers pointing to the same object
|
||
|
// as it will result in double free
|
||
|
ASSERT(!(Pointer != NULL && Pointer == rhs));
|
||
|
|
||
|
Clear();
|
||
|
Pointer = rhs;
|
||
|
}
|
||
|
|
||
|
void AssertNotEmpty() const
|
||
|
{
|
||
|
ASSERT(Get() != 0);
|
||
|
}
|
||
|
|
||
|
T * Pointer; // underlying pointer
|
||
|
}; // class AutoArray
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
///// AutoPointer - Pointer to single item with automatic freeing
|
||
|
//
|
||
|
// This class is used for storing objects allocated using new.
|
||
|
// For example:
|
||
|
//
|
||
|
// {
|
||
|
// AutoPointer<OBJECT> object(new OBJECT);
|
||
|
// if (!object)
|
||
|
// return OutOfMemory;
|
||
|
// object->Method();
|
||
|
// DoSomething(object.Get());
|
||
|
// // object is automatically deallocated
|
||
|
// }
|
||
|
|
||
|
template<class T>
|
||
|
class AutoPointer
|
||
|
{
|
||
|
typedef AutoPointer<T> self;
|
||
|
public:
|
||
|
// This constructor is made explicit so that compiler
|
||
|
// doesn't create implicit temporaries of type AutoPointer<T>
|
||
|
explicit AutoPointer(T * source = 0) : Pointer(source) {}
|
||
|
|
||
|
// Copy constructor and assignment operators need to ensure that
|
||
|
// pointer is freed only once
|
||
|
AutoPointer(self & rhs) : Pointer(rhs.Release()) {}
|
||
|
|
||
|
self & operator=(self & rhs)
|
||
|
{
|
||
|
SafeAssign(rhs.Release());
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
// Safe assignment for regular pointer
|
||
|
self & operator=(T * rhs)
|
||
|
{
|
||
|
SafeAssign(rhs);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
// Destructor is the whole point of having this class
|
||
|
~AutoPointer()
|
||
|
{
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
// This operator is for functions which allocate pointer and return it using T **
|
||
|
T ** operator&()
|
||
|
{
|
||
|
Clear();
|
||
|
Pointer = 0;
|
||
|
return &Pointer;
|
||
|
}
|
||
|
|
||
|
// The following 2 operators are for checks for NULL
|
||
|
operator BOOL() const
|
||
|
{
|
||
|
return (Pointer != 0);
|
||
|
}
|
||
|
|
||
|
BOOL operator!() const
|
||
|
{
|
||
|
return !Pointer;
|
||
|
}
|
||
|
|
||
|
// We disallow implicit conversion to pointer because it's dangerous,
|
||
|
// for example we don't want people do explicitly delete underlying pointer
|
||
|
// operator T* () const { return Pointer; }
|
||
|
|
||
|
T & operator*() const
|
||
|
{
|
||
|
AssertNotEmpty();
|
||
|
return *Get();
|
||
|
}
|
||
|
|
||
|
// Allow method calls using -> notation
|
||
|
T * operator->() const
|
||
|
{
|
||
|
AssertNotEmpty();
|
||
|
return Get();
|
||
|
}
|
||
|
|
||
|
// Obtain the underlying pointer
|
||
|
T * Get() const
|
||
|
{
|
||
|
return Pointer;
|
||
|
}
|
||
|
|
||
|
// Obtain the underlying pointer and release ownership,
|
||
|
// normally this is used to safely return the pointer from a function
|
||
|
// and let caller take care of deallocation
|
||
|
T * Release()
|
||
|
{
|
||
|
T * tmp = Pointer;
|
||
|
Pointer = 0;
|
||
|
return tmp;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
// Note that one should always assign a new value to Pointer after calling Clear()
|
||
|
void Clear()
|
||
|
{
|
||
|
delete Pointer;
|
||
|
}
|
||
|
|
||
|
void SafeAssign(T * rhs)
|
||
|
{
|
||
|
// We don't want to have 2 smart pointers pointing to the same object
|
||
|
// as it will result in double free
|
||
|
ASSERT(!(Pointer != NULL && Pointer == rhs));
|
||
|
|
||
|
Clear();
|
||
|
Pointer = rhs;
|
||
|
}
|
||
|
|
||
|
void AssertNotEmpty() const
|
||
|
{
|
||
|
ASSERT(Get() != 0);
|
||
|
}
|
||
|
|
||
|
T * Pointer; // underlying pointer
|
||
|
}; // class AutoPointer
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
///// AutoBuffer - Pointer to array of items with stack alloc and automatic freeing
|
||
|
//
|
||
|
// This class is used for creating buffers.
|
||
|
// For example:
|
||
|
//
|
||
|
// {
|
||
|
// AutoBuffer<BYTE, 100> buffer(count);
|
||
|
// if (!buffer)
|
||
|
// return OutOfMemory;
|
||
|
// buffer[0] = 0;
|
||
|
// DoSomething(buffer.Get());
|
||
|
// // buffer is automatically deallocated
|
||
|
// }
|
||
|
//
|
||
|
// Creates an array of count BYTEs. Reserves 100 bytes of stack space.
|
||
|
// If count <= 100, the reserved stack space is used for the buffer, else
|
||
|
// teh space is allocated on the heap.
|
||
|
|
||
|
template<class T, INT StackSize>
|
||
|
class AutoBuffer
|
||
|
{
|
||
|
public:
|
||
|
// This constructor is made explicit so that compiler
|
||
|
// doesn't create implicit temporaries of type AutoArray<T>
|
||
|
explicit AutoBuffer(INT requestedSize = -1)
|
||
|
: Size (requestedSize), // Allocated lazily if > StackSize
|
||
|
Pointer (StackBuffer) // Pointer is never NULL
|
||
|
{
|
||
|
if (requestedSize > StackSize)
|
||
|
{
|
||
|
// Stack buffer is not big enough
|
||
|
SetSize(requestedSize);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Clear()
|
||
|
{
|
||
|
if (Pointer != StackBuffer)
|
||
|
{
|
||
|
delete [] Pointer;
|
||
|
}
|
||
|
Pointer = StackBuffer;
|
||
|
Size = -1;
|
||
|
}
|
||
|
|
||
|
void SetSize(INT size)
|
||
|
{
|
||
|
// Fast case if existing buffer is big enough
|
||
|
|
||
|
if (size < Size || size < StackSize)
|
||
|
{
|
||
|
// Use existing buffer, whether it is the stack buffer or whether
|
||
|
// it is allocated separately.
|
||
|
Size = size;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (Pointer != StackBuffer)
|
||
|
{
|
||
|
// Exisiting buffer is not big enough
|
||
|
delete [] Pointer;
|
||
|
Pointer = StackBuffer;
|
||
|
}
|
||
|
|
||
|
Size = size;
|
||
|
|
||
|
if (Size > StackSize)
|
||
|
{
|
||
|
// Attempt to allocate a buffer bigger than stacksize.
|
||
|
// This doesn't have to succeed. (If it fails it leaves
|
||
|
// Size and Pointer in the defined 'unallocated' state.)
|
||
|
T *newBuffer = new T[Size];
|
||
|
if (newBuffer != NULL)
|
||
|
{
|
||
|
Pointer = newBuffer;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Cannot handle requested size
|
||
|
Size = -1; // Uninitialised
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
~AutoBuffer()
|
||
|
{
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
// The following 2 operators check whether the buffer needs allocating
|
||
|
|
||
|
operator BOOL()
|
||
|
{
|
||
|
return initialized();
|
||
|
}
|
||
|
|
||
|
BOOL operator!()
|
||
|
{
|
||
|
return !initialized();
|
||
|
}
|
||
|
|
||
|
// We disallow implicit conversion to pointer because it's dangerous,
|
||
|
// for example we don't want people do explicitly delete underlying pointer
|
||
|
// operator T* () const { return Pointer; }
|
||
|
// T & operator*() const { AssertNotEmpty(); return *Get(); }
|
||
|
|
||
|
// Provide index checked array lookup
|
||
|
template <typename INDEXTYPE>
|
||
|
T & operator[](INDEXTYPE ndx)
|
||
|
{
|
||
|
ASSERT(ndx >= 0 && ndx < Size);
|
||
|
return *(Pointer + ndx);
|
||
|
}
|
||
|
|
||
|
// Obtain the underlying pointer
|
||
|
T * Get()
|
||
|
{
|
||
|
return Pointer;
|
||
|
}
|
||
|
|
||
|
|
||
|
private:
|
||
|
|
||
|
BOOL initialized()
|
||
|
{
|
||
|
return Size >= 0 && (Size <= StackSize || Pointer != StackBuffer);
|
||
|
}
|
||
|
|
||
|
// Possible states:
|
||
|
//
|
||
|
// | Size <= StackSize | Size > StackSize
|
||
|
// | ----------------- | ----------------
|
||
|
// | |
|
||
|
// Pointer == StackBuffer | Buffer up to StackSize | Allocation failed
|
||
|
// ---------------------- | is available. |
|
||
|
// | |
|
||
|
// | |
|
||
|
// Pointer != StackBuffer | Dynamic buffer was | Heap buffer available
|
||
|
// ---------------------- | previously allocated | sufficient for Size.
|
||
|
// | since when SetSize has |
|
||
|
// | reduced required size. |
|
||
|
//
|
||
|
// Note that when SetSize reduces the required size after a heap buffer
|
||
|
// has already been allocated, the spare buffer space is NOT released.
|
||
|
// The client may call Clear() to guarantee freeing any heap buffer.
|
||
|
//
|
||
|
// If uninitialized, or if cleared, Size is recorded internally as -1,
|
||
|
// and BOOL tests return false. SetSize(0) is valid, always succeeds, and
|
||
|
// causes BOOL tests to return TRUE.
|
||
|
|
||
|
INT Size; // Requested size
|
||
|
T * Pointer; // Underlying pointer
|
||
|
|
||
|
// Note: be sure to keep the following buffer pointer size aligned.
|
||
|
T StackBuffer[StackSize]; // Note: prior pointer causes alignment
|
||
|
|
||
|
}; // class AutoBuffer
|
||
|
|
||
|
class AutoLock
|
||
|
{
|
||
|
CRITICAL_SECTION & CriticalSection;
|
||
|
public:
|
||
|
AutoLock(CRITICAL_SECTION & cs) : CriticalSection(cs)
|
||
|
{
|
||
|
::EnterCriticalSection(&CriticalSection);
|
||
|
}
|
||
|
~AutoLock()
|
||
|
{
|
||
|
::LeaveCriticalSection(&CriticalSection);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#endif // __AUTOPOINTERS_HPP_
|
||
|
|