You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
450 lines
9.4 KiB
450 lines
9.4 KiB
/*
|
|
* E X \ A U T O P T R . H
|
|
*
|
|
* Implementation of automatic-cleanup pointer template classes.
|
|
* This implementation is safe for use in NON-throwing environments
|
|
* (save for EXDAV & other store-loaded components).
|
|
*
|
|
* Copyright 1986-1998 Microsoft Corporation, All Rights Reserved.
|
|
*/
|
|
|
|
//----------------------------------------------------------------------//
|
|
//
|
|
// Automatic pointers defined here:
|
|
//
|
|
// auto_ptr<>
|
|
// auto_heap_ptr<>
|
|
// auto_handle<>
|
|
// auto_heap_array<>
|
|
// auto_ref_ptr<CRefCountedObject>
|
|
//
|
|
|
|
#ifndef _EX_AUTOPTR_H_
|
|
#define _EX_AUTOPTR_H_
|
|
|
|
#include <caldbg.h>
|
|
#include <calrc.h>
|
|
#include <ex\exmem.h>
|
|
|
|
#pragma warning(disable: 4284) // operator-> to a non UDT
|
|
|
|
// ========================================================================
|
|
//
|
|
// TEMPLATE CLASS auto_ptr
|
|
//
|
|
// Stripped down auto_ptr class based on the C++ STL standard one
|
|
//
|
|
// Calls delete on dtor.
|
|
// NO equals operator between these classes, as that hides
|
|
// the transfer-of-ownership. Handle those yourself, EXPLICITLY,
|
|
// like this:
|
|
// auto-ptr1 = auto-ptr2.relinquish();
|
|
//
|
|
template<class X>
|
|
class auto_ptr
|
|
{
|
|
protected:
|
|
X * px;
|
|
|
|
// NOT IMPLEMENTED
|
|
//
|
|
auto_ptr(const auto_ptr<X>& p);
|
|
auto_ptr& operator=(const auto_ptr<X>& p);
|
|
|
|
public:
|
|
|
|
// CONSTRUCTORS
|
|
//
|
|
explicit auto_ptr(X* p=0) : px(p) {}
|
|
~auto_ptr()
|
|
{
|
|
delete px;
|
|
}
|
|
|
|
// ACCESSORS
|
|
//
|
|
bool operator!()const { return (px == NULL); }
|
|
operator X*() const { return px; }
|
|
// X& operator*() const { Assert (px); return *px; }
|
|
X* operator->() const { Assert (px); return px; }
|
|
X* get() const { return px; }
|
|
|
|
// MANIPULATORS
|
|
//
|
|
X* relinquish() { X* p = px; px = 0; return p; }
|
|
X** operator&() { Assert (!px); return &px; }
|
|
void clear()
|
|
{
|
|
delete px;
|
|
px = NULL;
|
|
}
|
|
auto_ptr& operator=(X* p)
|
|
{
|
|
Assert(!px); // Scream on overwrite of good data.
|
|
px = p;
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
|
|
|
|
// ========================================================================
|
|
//
|
|
// TEMPLATE CLASS auto_handle
|
|
//
|
|
// auto_ptr for NT system handles.
|
|
//
|
|
// Closes the handle on dtor.
|
|
// NO equals operator between these classes, as that hides
|
|
// the transfer-of-ownership. Handle those yourself, EXPLICITLY,
|
|
// like this:
|
|
// auto-handle-1 = auto-handle-2.relinquish();
|
|
//
|
|
template<class X>
|
|
class auto_handle
|
|
{
|
|
private:
|
|
X handle;
|
|
|
|
// NOT IMPLEMENTED
|
|
//
|
|
auto_handle(const auto_handle<X>& h);
|
|
auto_handle& operator=(auto_handle<X>& h);
|
|
|
|
public:
|
|
|
|
// CONSTRUCTORS
|
|
//
|
|
auto_handle(X h=0) : handle(h) {}
|
|
~auto_handle()
|
|
{
|
|
if (handle && INVALID_HANDLE_VALUE != handle)
|
|
{
|
|
CloseHandle(handle);
|
|
}
|
|
}
|
|
|
|
// ACCESSORS
|
|
//
|
|
operator X() const { return handle; }
|
|
X get() const { return handle; }
|
|
|
|
// MANIPULATORS
|
|
//
|
|
X relinquish() { X h = handle; handle = 0; return h; }
|
|
X* load() { Assert(NULL==handle); return &handle; }
|
|
X* operator&() { Assert(NULL==handle); return &handle; }
|
|
void clear()
|
|
{
|
|
if (handle && INVALID_HANDLE_VALUE != handle)
|
|
{
|
|
CloseHandle(handle);
|
|
}
|
|
|
|
handle = 0;
|
|
}
|
|
|
|
auto_handle& operator=(X h)
|
|
{
|
|
Assert (handle == 0); // Scream on overwrite of good data
|
|
handle = h;
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
|
|
|
|
// ========================================================================
|
|
//
|
|
// TEMPLATE CLASS auto_ref_ptr
|
|
//
|
|
// Holds a ref on an object. Works with CRefCountedObject.
|
|
// Grabs a ref when a pointer is assigned into this object.
|
|
// Releases the ref when this object is destroyed.
|
|
//
|
|
template<class X>
|
|
class auto_ref_ptr
|
|
{
|
|
private:
|
|
|
|
X * m_px;
|
|
|
|
void init()
|
|
{
|
|
if ( m_px )
|
|
{
|
|
m_px->AddRef();
|
|
}
|
|
}
|
|
|
|
void deinit()
|
|
{
|
|
if ( m_px )
|
|
{
|
|
m_px->Release();
|
|
}
|
|
}
|
|
|
|
// NOT IMPLEMENTED
|
|
// We turn off operator new to try to prevent auto_ref_ptrs being
|
|
// created via new(). However, storext.h uses a macro to redefine new,
|
|
// so this line is only used on non-DBG.
|
|
#ifndef DBG
|
|
void * operator new(size_t cb);
|
|
#endif // !DBG
|
|
|
|
public:
|
|
|
|
// CONSTRUCTORS
|
|
//
|
|
explicit auto_ref_ptr(X* px=0) :
|
|
m_px(px)
|
|
{
|
|
init();
|
|
}
|
|
|
|
auto_ref_ptr(const auto_ref_ptr<X>& rhs) :
|
|
m_px(rhs.m_px)
|
|
{
|
|
init();
|
|
}
|
|
|
|
~auto_ref_ptr()
|
|
{
|
|
deinit();
|
|
}
|
|
|
|
// ACCESSORS
|
|
//
|
|
X& operator*() const { return *m_px; }
|
|
X* operator->() const { return m_px; }
|
|
X* get() const { return m_px; }
|
|
|
|
// MANIPULATORS
|
|
//
|
|
X* relinquish() { X* p = m_px; m_px = 0; return p; }
|
|
X** load() { Assert(NULL==m_px); return &m_px; }
|
|
X* take_ownership(X* p) { Assert(NULL==m_px); return m_px = p; }
|
|
void clear()
|
|
{
|
|
deinit();
|
|
m_px = NULL;
|
|
}
|
|
auto_ref_ptr& operator=(const auto_ref_ptr<X>& rhs)
|
|
{
|
|
if ( m_px != rhs.m_px )
|
|
{
|
|
deinit();
|
|
m_px = rhs.m_px;
|
|
init();
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
auto_ref_ptr& operator=(X* px)
|
|
{
|
|
if ( m_px != px )
|
|
{
|
|
deinit();
|
|
m_px = px;
|
|
init();
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
// ========================================================================
|
|
//
|
|
// TEMPLATE CLASS auto_heap_ptr
|
|
//
|
|
// An auto_ptr class based on the heap instead of new.
|
|
//
|
|
// Calls ExFree() on dtor.
|
|
// NO equals operator between these classes, as that hides
|
|
// the transfer-of-ownership. Handle those yourself, EXPLICITLY,
|
|
// like this:
|
|
// auto-heap-ptr1 = auto-heap-ptr2.relinquish();
|
|
//
|
|
template<class X>
|
|
class auto_heap_ptr
|
|
{
|
|
private:
|
|
X * m_px;
|
|
|
|
// NOT IMPLEMENTED
|
|
//
|
|
auto_heap_ptr (const auto_heap_ptr<X>& p);
|
|
auto_heap_ptr& operator= (const auto_heap_ptr<X>& p);
|
|
//void * operator new(size_t cb);
|
|
|
|
public:
|
|
|
|
// CONSTRUCTORS
|
|
//
|
|
explicit auto_heap_ptr (X* p=0) : m_px(p) {}
|
|
~auto_heap_ptr()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
// ACCESSORS
|
|
//
|
|
// NOTE: this simple cast operator (operator X*()) allows
|
|
// the [] operator to function.
|
|
//$REVIEW: Should we add an explicit [] operator?
|
|
operator X*() const { return m_px; }
|
|
X* operator->() const { Assert (m_px); return m_px; }
|
|
X* get() const { return m_px; }
|
|
|
|
//X& operator[] (UINT index) const { return *(m_px + index); }
|
|
//X& operator[] (UINT index) const { return m_px[index]; }
|
|
|
|
// MANIPULATORS
|
|
//
|
|
X* relinquish() { X* p = m_px; m_px = 0; return p; }
|
|
X** load() { Assert(!m_px); return &m_px; }
|
|
//$REVIEW: Can we migrate all users of operator&() to use load() instead???
|
|
//$REVIEW: Benefit: it's more explicit. Detriment: need to change existing code.
|
|
X** operator&() { Assert (!m_px); return &m_px; }
|
|
void clear()
|
|
{
|
|
if (m_px) // Release any object we're holding now
|
|
{
|
|
ExFree (m_px);
|
|
}
|
|
m_px = NULL;
|
|
}
|
|
|
|
// Realloc
|
|
//$REVIEW:
|
|
// This operator is technically NOT safe for store-side code!
|
|
// It makes it easy to ignore memory failures.
|
|
// (However, it is currently so ingrained in our vocabulary that
|
|
// removing it will touch a very large number of files: )
|
|
// For now, to be safe, callers MUST check the value of their
|
|
// object (using .get()) after calling this function.
|
|
//
|
|
void realloc(UINT cb)
|
|
{
|
|
VOID * pvTemp;
|
|
|
|
if (m_px)
|
|
pvTemp = ExRealloc (m_px, cb);
|
|
else
|
|
pvTemp = ExAlloc (cb);
|
|
Assert (pvTemp);
|
|
|
|
m_px = reinterpret_cast<X*>(pvTemp);
|
|
}
|
|
//$REVIEW: end
|
|
|
|
// Failing Realloc
|
|
//
|
|
BOOL frealloc(UINT cb)
|
|
{
|
|
VOID * pvTemp;
|
|
|
|
if (m_px)
|
|
pvTemp = ExRealloc (m_px, cb);
|
|
else
|
|
pvTemp = ExAlloc (cb);
|
|
if (!pvTemp)
|
|
return FALSE;
|
|
|
|
m_px = static_cast<X*>(pvTemp);
|
|
return TRUE;
|
|
}
|
|
|
|
// NOTE: This method asserts if the auto-pointer already holds a value.
|
|
// Use clear() or relinquish() to clear the old value before
|
|
// taking ownership of another value.
|
|
//
|
|
void take_ownership (X * p)
|
|
{
|
|
Assert (!m_px); // Scream on overwrite of good data.
|
|
m_px = p;
|
|
}
|
|
// NOTE: This operator= is meant to do exactly the same as take_ownership().
|
|
//
|
|
auto_heap_ptr& operator= (X * p)
|
|
{
|
|
Assert (!m_px); // Scream on overwrite of good data.
|
|
m_px = p;
|
|
return *this;
|
|
}
|
|
|
|
};
|
|
|
|
// ========================================================================
|
|
//
|
|
// TEMPLATE CLASS auto_co_task_mem
|
|
//
|
|
// Stripped down auto_co_task_mem class based on the C++ STL standard one
|
|
//
|
|
// Calls CoTaskMemFree on dtor.
|
|
// NO equals operator between these classes, as that hides
|
|
// the transfer-of-ownership. Handle those yourself, EXPLICITLY,
|
|
// like this:
|
|
// auto-co_task_mem1 = auto-co_task_mem2.relinquish();
|
|
//
|
|
template<class X>
|
|
class auto_co_task_mem
|
|
{
|
|
protected:
|
|
X * m_px;
|
|
|
|
// NOT IMPLEMENTED
|
|
//
|
|
auto_co_task_mem(const auto_co_task_mem<X>& p);
|
|
auto_co_task_mem& operator=(const auto_co_task_mem<X>& p);
|
|
|
|
public:
|
|
|
|
// CONSTRUCTORS
|
|
//
|
|
explicit auto_co_task_mem(X* p=0) : m_px(p) {}
|
|
~auto_co_task_mem()
|
|
{
|
|
CoTaskMemFree(m_px);
|
|
}
|
|
|
|
// ACCESSORS
|
|
//
|
|
X* operator->() const { Assert (m_px); return m_px; }
|
|
X* get() const { return m_px; }
|
|
|
|
// MANIPULATORS
|
|
//
|
|
X* relinquish() { X* p = m_px; m_px = 0; return p; }
|
|
X** load() { Assert(!m_px); return &m_px; }
|
|
X** operator&() { Assert (!m_px); return &m_px; }
|
|
void clear()
|
|
{
|
|
CoTaskMemFree(m_px);
|
|
m_px = NULL;
|
|
}
|
|
|
|
// NOTE: This method asserts if the auto-pointer already holds a value.
|
|
// Use clear() or relinquish() to clear the old value before
|
|
// taking ownership of another value.
|
|
//
|
|
void take_ownership (X * p)
|
|
{
|
|
Assert (!m_px); // Scream on overwrite of good data.
|
|
m_px = p;
|
|
}
|
|
|
|
auto_co_task_mem& operator=(X* p)
|
|
{
|
|
Assert(!m_px); // Scream on overwrite of good data.
|
|
m_px = p;
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
#endif //!_EX_AUTOPTR_H_
|