65.9K
CodeProject 正在变化。 阅读更多。
Home

ATL 的 CComSafeArray 的二维包装器

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.91/5 (8投票s)

2003 年 5 月 9 日

公共领域

2分钟阅读

viewsIcon

71673

downloadIcon

517

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

© . All rights reserved.