ATLVisual C++ 7.1Visual C++ 8.0Visual C++ 7.0Windows 2003Windows 2000Windows XP中级开发Visual StudioWindowsC++
ATL 的 CComSafeArray 的二维包装器
SafeArray 封装器,用于简化和加速 2D CComSafeArray<>
引言
这是一个尝试,旨在使使用 2D SAFEARRAYS
更容易接受,同时提供类似于 C++ 和 VB 的访问方式。从 ATL7 开始,Microsoft 引入了一个 SAFEARRAY
封装类 CComSafeArray<T>
,它提供了一些有用的服务,例如锁定和销毁,以及使用标准 C++ "[]
" 符号提供向量访问。然而,它非常慢,并且对于 2D (或更多) 数组几乎没有简化。此外,MSDN 中的文档创建了一个 3x3 数组,然后用一个 2x3 矩阵填充它,完全掩盖了幕后发生了什么,因为行数等于列数。
此封装类试图解决以下问题:
- 提供行优先 (C++) 和列优先 (VB) 访问机制,因为 VB 似乎是 2D 数组的最大用户,但我更习惯 C++ 排序。 默认是类似于 C++ 的内存布局:
SArray2<float,false,false>
;a(3,4)
具有与float a[3][4]
相同的内存布局。 - 加快元素访问时间。这非常重要,我看到了 40 倍的改进,因为
CComSafeArray
已经锁定了数据。 - 将封装器限制为基于零的 2D 数组。现在这是 VB 的默认设置,并且是本机 C++ 数组所必需的。
- 提供类似于 VB 的构造函数作为选项,以便像
SArray2<float,false,false> a(3,4)
这样的声明实际上以与dim a(3,4) as single
在 VB 中相同的方式声明。 它具有与 C++ 中的a[5][4]
相同的内存布局。 - 继承自 CComSafeArray 并避免使用任何其他状态信息,这允许与 CComSafeArray 的透明性。 不适用于 2D SafeArrays 的方法已通过将它们声明为私有来屏蔽。
- 与 ATL 头文件“atlsafe.h”一起使用,该文件可以在任何地方使用,而不仅仅是 ATL 项目。
包装器
它足够小可以包含
// include ATL header that contains CComSafeArray<T> // Writtten by M. Gray 5/03, donated to public domain, use at your own risk. #include <atlsafe.h> // Wrapper for ATL's CComSafeArray<T> providing 2D access. // CComSafeArray<T> is great for 1D vectors but has awkward nD handling template<typename T, bool rowMajor=true, bool extraElement=false> class SArray2 : public CComSafeArray<T> { // These functions are overridden and made private since they are not // useful for 2D arrays void Add(){} // N/A void Create(){} // N/A void GetAt(){} // N/A void GetDimensions(){} // N/A void GetLowerBound(){} // N/A void SetAt(){} // N/A void operator[](int){} // N/A public: SArray2(): CComSafeArray<T>(){} SArray2(UINT a_rows, UINT a_cols) { SAFEARRAYBOUND bounds[2]; bounds[0].cElements = (UINT)extraElement + (rowMajor ? a_cols : a_rows); bounds[0].lLbound = 0; bounds[1].cElements = (UINT)extraElement + (rowMajor ? a_rows : a_cols); bounds[1].lLbound = 0; CComSafeArray<T>::Create(bounds ,2); } // Attach to safearray but check for 2D and zero base HRESULT Attach(const SAFEARRAY *psaSrc) { ATLASSERT(psaSrc->cDims==2 && psaSrc->rgsabound[0].lLbound==0 && psaSrc->rgsabound[1].lLbound==0); return CComSafeArray<T>::Attach(psaSrc); } T& operator()(UINT a_row, UINT a_col) { ATLASSERT(m_psa->rgsabound[rowMajor?0:1].cElements > a_row); ATLASSERT(m_psa->rgsabound[rowMajor?1:0].cElements > a_col); return static_cast<T *>(m_psa->pvData) [m_psa->rgsabound[1].cElements * (rowMajor ? a_row : a_col) + (rowMajor ? a_col : a_row)]; } // this method will return the number of elements in a specific zero // based dimension only ULONG GetCount(UINT uDim = 0) const {return CComSafeArray<T>::GetCount(rowMajor ? 1-uDim : uDim);} // The zero based array dimension for which to get the upper bound. // If omitted, the default is 0. ULONG GetUpperBound(UINT uDim = 0) const {return CComSafeArray<T>::GetUpperBound(rowMajor ? 1-uDim : uDim);} // A pointer to a SAFEARRAYBOUND structure that contains information on // the number of elements and the lower bound of an array HRESULT Resize(const SAFEARRAYBOUND *pBound) {return CComSafeArray<T>::Resize(pBound);} };
使用代码
此代码易于使用
SArray2<float> sa(2,3); sa(0,1)=1.3f;
SAFEARRAY 的数据部分具有与 float sa[2][3]
相同的内存布局和含义
float sa[2][3] sa[0][1]=1.3f;
为了了解直接使用 CComSafeArray 的代码有多难看,这完成了相同的事情,只是速度较慢
SAFEARRAYBOUND bounds[2]; bounds[0].cElements = 3; bounds[0].lLbound = 0; bounds[1].cElements = 2; bounds[1].lLbound = 0; CComSafeArray<float> a; a.Create(bounds ,2); long index[2]; float fval=1.3f; index[0]=1; // note: column major ordering of SafeArray Access index[1]=0; a.MultiDimSetAt(index, fval);
包含的测试工具提供各种排列和函数的示例。 它没有任何用处,但显示了行优先和列优先声明的各种形式以及 VB 中等效的“k+1” DIM。
历史
初始版本 5/8/03